c++ - 为什么这种打破封装的方式在 C++ 中起作用?

标签 c++ class inheritance polymorphism

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

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;
}

输出是(注意继承是 protected ):

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;

如果我将继承从 protected 更改为 public,那么代码可以运行,并且我会得到以下输出:

From Y

在我看来,当继承是公共(public)的(因为 Y::f 是从 X 调用的)时,对函数“f”的调用没有强制执行私有(private)访问限制。 在运行这段代码之前,我认为由于访问限制,我应该总是得到一个编译时错误(事实证明这是错误的)。

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

最佳答案

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

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

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

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

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

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

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

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

至于为什么用protected inheritance的时候编译不通过,嗯,是因为inheritance是protected的。如果 Y 私有(private)或 protected 地继承自 X,则您无法使用 Y 类型的对象获取指向 X 的指针>.

关于c++ - 为什么这种打破封装的方式在 C++ 中起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19342868/

相关文章:

Python类继承初始化

c++ - 如何使用 Luabind 和 C++ 创建 Assets 管理类?

inheritance - JPA TABLE_PER_CLASS继承: How to only SELECT superclass entries?

c++ - 搜索值并在 vector 中返回其索引的最有效方法?

javascript - Canvas 类 JavaScript

c++ - 如何禁止 C++ 派生类从基类派生,但允许从另一个派生类派生

c++ - 嵌套类设计 C++ virtual

Python抽象方法默认逻辑,super()方法

c++ - 将 vector 转换为 Mat 中的行或 OpenCV 中的空 Mat 的有效方法?

c++ - 如何在最小化每秒更新影响的同时存储和推送模拟状态?