2013-10-13 34 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