這個話題是源自于一個面試題,我在網上查了一下有不少這方面的解說!我自己整理了一下,選擇了一個自認為是最優方案!
我們從最簡單的開始:
首先,大家都知道要阻止類被實例化,可以通過使用private or protected 關鍵字來聲明默認構造函數。那么在阻止類被繼承的時候,我們需要用到這個技巧。其次,阻止類被繼承還需要使用private來控制繼承的基類。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
namespace SamplePrivate { #ifdef NDEBUG class Sealed { protected : Sealed() {}; friend class SampleSealedClass; // 設置友類,以便訪問Sealed的構造函數 }; class SampleSealedClass : private virtual Sealed { }; #else class SampleSealedClass {} #endif } |
這樣我們就可以實例化SampleSealedClass,并且還不用擔心被繼承了。不過還是要解釋一下為什么阻止了繼承?
當我們寫出下面的代碼時,編譯器在編譯過程中做了什么呢?
1
2
3
|
class subclass : public SampleSealedClass { }; |
首先,當你在實例化subclass的時候,會先調用SampleSealedClass的構造函數,而在這之前會調用Sealed類的默認構造函數,但是我們發現Sealed是不能被實例化的,并且通過private virtual的繼承只能被SampleSealedClass調用,因此這很好的阻止了類被繼承。但是這里我們只能完成一個類被不被繼承,那么是否有更好的方法來實現阻止任意類被繼承呢?
那就需要用到模板了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#ifdef NDEBUG namespace SealedClasses { class Sealed { protected : Sealed() {} }; template < class T> class TypeWapper { public : typedef T type; }; } template < typename T> class BaseSealed : private virtual SealedClasses::Sealed { friend class SealedClasses::TypeWapper<T>::type; }; #else template < typename T> class BaseSealed { }; #endif |
這里的TypeWapper主要是將外部類型傳遞到SealedClasses的,從而能得到訪問Sealed構造函數的能力。不過這段代碼在GCC4.0中通過編譯,而在vs2008中不能通過。可以向下面這樣來引用:
1
2
3
4
5
6
7
8
9
10
11
|
class subclass : BaseSealed<subclass> { public : subclass() { cout << "subclass" << endl; } }; // 下面這個會編譯失敗 class ssubclass : public subclass { public : ssubclass() { cout << "ssubclass" << endl; } }; |
將想法付諸于實踐,借此來影響他人是一個人存在的真正價值
總結
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注服務器之家的更多內容!
原文鏈接:https://www.cnblogs.com/moonz-wu/archive/2008/05/07/1186065.html