C++設計一個不能被繼承的類,為什么必須是虛繼承?原因分析
使用友元、私有構造函數、虛繼承等方式可以使一個類不能被繼承,可是為什么必須是虛繼承?背后的原理又是什么?
用C++實現一個不能被繼承的類(例1)
#include <iostream> using namespace std;template <typename T> class Base{ friend T; private: Base(){ cout << "base" << endl; } ~Base(){} };
class B:virtual public Base<B>{ //一定注意 必須是虛繼承 public: B(){ cout << "B" << endl; } };
class C:public B{ public: C(){} //繼承時報錯,無法通過編譯 };
int main(){ B b; //B類無法被繼承 //C c; return 0; }</pre>
類Base的構造函數和析構函數因為是私有的,只有Base類的友元可以訪問,B類在繼承時將模板的參數設置為了B類,所以構造B類對象時們可以直接訪問父類(Base)的構造函數。
為什么必須是虛繼承(virtual)呢?
參見 c++Primer 4th 第17.3.7節 特殊的初始化語義
通常每個類只初始化自己的直接基類,但是在虛繼承的時候這個情況發生了變化,可能導致虛基類被多次初始化,這顯然不是我們想要的。(例2: AA,AB都是類A的派生類,然后類C又繼承自AA和AB,如果按之前的方法會導致C里面A被初始化兩次,也會存在兩份數據)
為了解決重復初始化的問題,從具有虛基類的類繼承的類在初始化時進行了特殊處理,在虛派生中,由最低層次的派生類的構造函數初始化虛基類。在我們上面的例1中就是由C的構造函數控制如何進行虛基類的初始化。
為什么B類不能被繼承?
回到例1,因為B是Base的友元,所以B對象可以正常創建,但由于B使用了虛繼承,所以如果要創建C對象,那么C類的構造函數就要負責虛基類(Base)的構造,但是Base的構造函數是私有的,C沒有訪問的權限(ps:友元關系不能被繼承的),所以例1中的C類在編譯時就會報錯。這樣B類就不能被繼承了。
----------------------------------------------------
來自:http://my.oschina.net/cuilili/blog/323696