一道筆試題的思考:
記得,找工作時,遇到了這樣的一道筆試題。
記不清是那個公司的筆試題,反正覺得自己當時還真費了一點功夫的,但是也就搞定了一部分,結果還是被另一部分給鄙視啦!
現在靜下來分析實現如下:
題目:用C++設計一個不能被繼承的類
不能被繼承?不能被繼承?不能被繼承?按照繼承的理論知識分析,我們只要把類的構造函數設置為私有的,即可解決問題。
因為那樣的話,子類就沒有辦法訪問基類的構造函數,從而就阻止了進行子類構造對象的任務實現,也就達到了不可繼承的目的。
但是,假設那樣,這個類我們在其它地方怎么使用呢?那這樣子給我們的利用也造成了一定的障礙。
好了。你是不是也想到了,定義靜態方法,在方法內部實現一個對象,然后返回它的指針。
Ok?那怎么釋放掉呢?再照樣設計一個釋放內存函數,問題就會迎刃而解。
OK。按照這個邏輯分析。示例代碼如下:
1 #include<iostream> 2 using namespace std; 3 4 class A 5 { 6 public: 7 static A * Construct(int n) 8 { 9 A *pa = new A; 10 pa->num = n; 11 cout << "num is:" << pa->num << endl; 12 return pa; 13 } 14 static void Destruct(A * pIntance) 15 { 16 delete pIntance; 17 pIntance = NULL; 18 } 19 20 private: 21 A(){} 22 ~A(){} 23 24 public: 25 int num; 26 }; 27 28 void main() 29 { 30 A *f = A::Construct(9); 31 cout << f->num << endl; 32 A::Destruct(f); 33 }
好了,這個類就這樣子。按照理論分析,我們的實踐結果也是完全成立的。
但是,這個題,它比較有挑戰性,什么意思呢?難道你沒有發現,咱們這水平也就僅僅有面試資格,還不可以破格錄用的。
怎么啦?你可能會反問我。難道你真的沒有看明白?確定沒有看明白?如果是真的話,那我就告訴你吧!
咱們的類不可以實現在棧上創建對象。也就是說,僅僅只可以在堆上構建任何的一個對象,而在棧上就無能為力了。
私有的構造函數極大的局限性就這樣一覽無余了。(其實,上面類設計即是一種只可以創建堆對象,不可以創建棧對象的情況。)
好吧!我們修改它,也就是所謂的為它打“補丁吧”,請看示例代碼:
1 #include<iostream> 2 using namespace std; 3 4 template <typename T> 5 class Base 6 { 7 friend T; 8 private: 9 Base() {} 10 ~Base() {} 11 }; 12 13 class Finalclass : virtual public Base<Finalclass> 14 { 15 public: 16 Finalclass() {} 17 ~Finalclass() {} 18 }; 19 20 class TestClass : public Finalclass 21 { 22 }; 23 24 void main() 25 { 26 Finalclass* p = new Finalclass; // 堆上對象 27 Finalclass fs; // 棧上對象 28 // TestClass tc; // 基類構造函數私有,不可以被繼承。因此不可以創建棧上對象。 29 30 system("pause"); 31 }
OK 代碼碼完。現在分析Finalclass類:
繼承於Base類,Base為虛基類,因為它是Base的友元,所以,它可以訪問基類的私有構造函數,以及析構函數。編譯運行時是正確的。
也就是說,可以創建堆上的對象,並且可以構建棧上的對象。
可否繼承?假如它作為一個基類被另一個類繼承,編譯時是完全可以通過的。這一點沒有什么疑問。
但問題就在需要構建對象時:
當派生類TestClass在構造對象時,因為是虛繼承,所以派生類TestClass的構造函數會直接去調用Base基類的構造函數,而Base的構造函數是私有的。編譯錯誤!
這就是一個真正不能被繼承的類。