2013-10-13 35 views
3

我试过运行下面这段代码。请注意,该函数“G”调用函数“f”,这是在X公开,但在Y.私人为什么打破封装在C++中工作?

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 

在我看来,仿佛并没有强制执行的调用私有访问限制的功能“F”的时候, INH eritance是公开的(因为Y :: f是从X中调用的)。 运行这段代码之前,我认为我应该总是因为访问限制(这被证明是错误的)而导致编译时错误。

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

+0

[继承:'A'可能是'B'的一个不可访问的基础](http://stackoverflow.com/questions/9661936/inheritance-a-is-an-inaccessible-base-of-b) – deepmax

+0

不是。虽然这是一个很好的职位。 – Shookie

回答

6

封装没有破坏:当您使用公共继承时,您的方法在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私下或受保护继承,那么您将无法获得指向X的指针,其类型为Y