C++中如何防止類被繼承


  在C++學習中,尤其在涉及類這一內容時,我們往往會遇到這樣一個問題:如何設計一個類,要求該類不能被繼承?

  最簡單的方法就是將該類的構造函數聲明為私有方法,但是這又帶來另一個弊端:那就是該類本身不能生成對象了,當然這樣能夠滿足該類不能被繼承的要求,卻得不償失。下面介紹一種比較巧妙的方法來供大家參考,也算是自己學習中的一個小小的總結吧。

  主要思想就是:通過一個構造函數和析構函數都是私有的輔助類來實現的。假設不想被繼承的類為A,我們可以將A聲明為輔助類的一個友元,另外,為了讓A的子類B能夠調用輔助類的構造函數,對於A則虛繼承輔助類。說起來有點麻煩,下面直接上碼:

 1 #include <iostream>
 2 using namespace std;
 3 class A;
 4 class Assistant
 5 {
 6  private: 
7
friend A;
8
Assistant(){}; 9 ~Assistant(){}; 10 }; 11 12 class A : public virtual Assistant 13 { 14 public: 15 A(){}; 16 ~A(){}; 17 }; 18 19 class B : public A 20 { 21 public: 22 B(){}; 23 ~B(){}; 24 }; 25 26 int main(int argc, char* argv[]) 27 { 28 A a; // 可以構造 29 B b; // 不能構造 30 return 0; 31 }

  這樣的話就實現了A的派生類不能繼承A類的一個設計,但是每次聲明一個非繼承類都要在Assistant類中添加一個友元,這樣很不方便,而且一旦非繼承的類多了,Assistant類就會看起來很臃腫,這時我們就可以采用泛型編程中的模板技術:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 template <class T>
 5 class Assistant
 6 {
 7  private:
 8     friend  T; 
9
Assistant(){}; 10 ~Assistant(){}; 11 }; 12 13 class A : public virtual Assistant <A> 14 { 15 public: 16 A(){}; 17 ~A(){}; 18 }; 19 20 class B : public A 21 { 22 public: 23 B(){}: 24 ~B(){}; 25 }; 26 27 int main(int argc, char* argv[]) 28 { 29 A a; // 可以構造 30 B b; // 不能構造 31 return 0; 32 }

  這樣的話,就能夠實現多個不被繼承的類,公用同一個輔助類Assistant,而無需在Assistant類中添加任何多余的聲明。任何類想設計成不被繼承,只需虛繼承Assistant類即可。

  到現在為止,可能有些人對虛繼承(virtual)還不是很了解,為什么這里A類一定要虛繼承Assistant類呢?

  虛繼承的功能是:當出現了菱形繼承體系的時候,子孫類不會繼承多個原始祖先類。這里有什么用呢?這會導致基類的初始化任務必須由繼承體系中最底層的類完成,即B類聲明對象時,必須直接調用Assistant類中的構造函數,而不是先調用A類的構造函數,然后再通過A類來調用Assistant類的構造函數,如果是這樣的話,那么上面B類聲明對象b時,是可以構造的。所以A類必須虛繼承Assistant而不是簡單的public繼承。為了進一步解釋這段說明,我們看看下面這段代碼:

 1 #include <iostream>
 2 using namaspace std;
 3 
 4 template <class T>
 5 class Assistant
 6 {
 7  private:
 8      friend  T; 
9
Assistant(){}; 10 ~Assistant(){}; 11 }; 12 13 class A : public Assistant <A> 14 { 15 public: 16 A(){}; 17 ~A(){}; 18 }; 19 20 class B : public A 21 { 22 public: 23 B(){}; 24 ~B(){}; 25 }; 26 27 int main(int argc, char* argv[]) 28 { 29 A a; // 可以構造 30 B b; // 可以構造! 31 }

  所以,當A直接public繼承Assistant,而不是virtual public繼承Assistant時,A類還是可以被B類繼承的,因為這個時候B確實是可以成功的聲明對象。

  具體的原因就是我上面說到的:由於A不是virtual public繼承Assistant的,所以B在聲明對象時,是通過A類來調用祖先類Assistant的構造函數的,而A類是Assistant的友元類,故可以調用被私有化的Assistant()方法,所以此時,B b;可以成功構造!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM