c++不像java一樣有純介面類的的文法,但我們可以通過一些手段實現相同的功能。
一:
考慮這樣的代碼:
class A { protected: virtual ~A() { cout << __FUNCTION__ << endl; } }; class B : public A { public: virtual ~B() { cout << __FUNCTION__ << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { A* p1 = new A; //[1]有問題 delete p1; B* p2 = new B; delete p2; //[2]沒問題的 A* p3 = new B; delete p3; //[3] 有問題 return 0; } |
通過在類中,將類的建構函式或者解構函式申明成protected
,可以有效防止類被執行個體話,要說實用的話,建構函式是protected更有用,肯定能保證類不會被執行個體化,而如果解構函式是protected的話,建構函式不是protected的話,還可能存在編譯通過的漏洞,如下:
A:
class A { protected: A() { cout << __FUNCTION__ << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { A* p1 = new A; //編譯不通過,無法訪問protected建構函式 delete p1; return 0; } |
B:
class A { protected: ~A() { cout << __FUNCTION__ << endl; } };int _tmain(int argc, _TCHAR* argv[]) { A* p1 = new A; //編譯通過,此時因為僅僅是用到了A的建構函式,還不需要它的解構函式 return 0; }
|
C:
class A { protected: ~A() { cout << __FUNCTION__ << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { A* p1 = new A; delete p1; //編譯失敗,因為編譯器發現A的解構函式是protected return 0; } |
所以,一種可行的辦法貌似是這樣的:
class A { protected: virtual ~A() { cout << __FUNCTION__ << endl; } }; class B : public A { }; int _tmain(int argc, _TCHAR* argv[]) { B* p =new B; //這種情況下確實是可行的 delete p; return 0; }
|
由於B public繼承自A,所以其可以完全訪問A的構造或解構函式,但是:
int _tmain(int argc, _TCHAR* argv[]) { A* p =new B; delete p; //由於p變成指向A的指標,字面上編譯器需要知道A的解構函式,然後A的解構函式又是protected return 0; }
|
即便像這樣B顯示重載了A的解構函式:
class A { protected: virtual ~A() { cout << __FUNCTION__ << endl; } }; class B : public A { public: virtual ~B() { cout << __FUNCTION__ << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { A* p =new B; delete p; //也還是不行,因為重載是運行時的事情,在編譯時間編譯器就認定了A的解構函式,結果無法擷取 return 0 }
|
小結:
貌似用protected這樣的方法並不是很恰當,雖然在遵守一定規則的情況下確實有他的實用價值,但並不是很通用。
二:
其實上面protected的思路是對的,無非是讓父類無法執行個體化,那麼為了讓父類無法執行個體化,其實還有一個方法,使用純虛函數。
class A { public: //這裡就不用protected了 virtual ~A() = 0; }; class B : public A { }; int _tmain(int argc, _TCHAR* argv[]) { B* p =new B; delete p; return 0; }
|
這樣寫貌似不錯,以往大家都把類中的一般成員函數寫成純虛的,這次將解構函式寫成純虛的,更加增加通用性,編譯也通過了,但就是在連結的時候出問題,報錯說找不到A的解構函式的實現,很顯然嗎,因為A的析構是純虛的嗎。
class A { public: //這裡就不用protected了 virtual ~A() = 0 //它雖然是個純虛函數,但是預設實現,可以有 { //這個文法很好很強大,經過小強的指點終於高清了他的用法(完全是為了實現其介面類而弄的文法吧) cout << __FUNCTION__ << endl; } }; class B : public A { }; int _tmain(int argc, _TCHAR* argv[]) { B* p =new B; delete p; A* p2 =new B; delete p2; //不用擔心編譯器報錯了,因為此時A的解構函式是public return 0; }
|
如此終於大功告成了,注意,不能將建構函式替代上面的解構函式的用法,因為建構函式是不允許作為虛函數的。
補充:以上那個文法就真的只是為了這種情況而存在的,因為一般我們在虛類中申明的介面:
virtual foo() = 0;
virtual foo() = 0 {}
這兩種寫法是完全沒有區別的,純虛函數的預設實現,僅僅在它是解構函式中才有意義!!!
所以可以說,老外是完全為了這一個目的而發明了這種文法...
最終的介面類
class Interface { public: virtual ~Interface() = 0 {} };
|
應該挺完美的了吧,hiahia