【问题标题】:Why does this breaking of encapsulation work in C++?为什么这种打破封装在 C++ 中起作用?
【发布时间】:2013-10-20 23:50:35
【问题描述】:

我已尝试运行以下代码。请注意,函数“g”调用函数“f”,该函数在 X 中是公共的,但在 Y 中是私有的。

class X{
    public:
        virtual void f(void){cout<<"From X\n";}
        virtual void g(X* x) { x->f();}
};

class Y: protected X{
    private:
        void f(void){cout<<"From Y\n";}
};

int main() {
    Y y = Y();
    Y *py = &y;
    X* px = py;
    py->g(py);

    return 0;
}

输出是(注意继承受到保护):

prog.cpp: In function ‘int main()’:
prog.cpp:18:10: error: ‘X’ is an inaccessible base of ‘Y’
  X* px = py;
          ^
prog.cpp:7:16: error: ‘virtual void X::g(X*)’ is inaccessible
   virtual void g(X* x) { x->f();}
                ^
prog.cpp:19:10: error: within this context
  py->g(py);
          ^
prog.cpp:19:10: error: ‘X’ is not an accessible base of ‘Y’
prog.cpp:19:10: error: ‘X’ is an inaccessible base of ‘Y’
prog.cpp:18:5: warning: unused variable ‘px’ [-Wunused-variable]
  X* px = py;

如果我将继承从受保护更改为公共,则代码可以正常工作,我会得到以下输出:

From Y

在我看来,当继承是公共的(因为 Y::f 是从 X 调用的)时,对函数“f”的调用没有强制执行私有访问限制。 在运行这段代码之前,我想我应该总是因为访问限制而出现编译时错误(这被证明是错误的)。

以某种方式将继承从 public 更改为 protected 解决了这个问题,并且不会启用对 Y::f 的调用。 谁能解释一下为什么?

【问题讨论】:

  • 对于我来说有点过于语言律师化,但我知道您永远不会因为访问限制而遇到运行时错误。访问仅适用于编译时。
  • 不是。虽然这是一篇好文章。

标签: c++ class inheritance polymorphism


【解决方案1】:

没有破坏封装:当您使用公共继承时,您的方法在X 上是公共的,并且Y 类的对象“也是”X 类型。

C++ 中的覆盖与访问规则是正交的。您可以使用私有方法覆盖公共方法。这可能是糟糕的设计,因为您总是可以通过对基类的引用来调用它。

这意味着当你有一个指向X 的指针时,只有class X 的访问限制适用。

请注意,您也可以覆盖私有方法(请参阅“模板方法”GOF 设计模式)

class X {
public:
    void f () { g (); }

private:
    virtual void g () = 0;
};

class Y : public X
{
private:
    void g () { std::cout << "from X\n"; }
};

因此,您可能希望尽可能将虚拟函数设为私有。

至于为什么在使用受保护的继承时不能编译,嗯,是因为继承是受保护的。如果YX 私下或受保护地继承,则您无法使用Y 类型的对象获得指向X 的指针。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-23
    • 1970-01-01
    • 2017-04-11
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多