昨天提到了子在構造函數和析構函數中調用虛函數的問題。白天的時候翻了一下《深入理解C++對象模型》,結果還真發現一點兒有趣的東西。
文中如是說:很多C++新手會驚奇的發現純虛函數竟然可以定義(在聲明的基類中定義),並且可以被調用(靜態調用)!看來我還是新手啊,廢話少說,上代碼!
#include <iostream> using namespace std; class Base{ public: Base(){} void callVirFunc(); virtual ~Base(){}; private: virtual void virFunc() = 0;//注意是私有的哦! }; class Derived:public Base{ public: Derived(){} private: virtual void virFunc();//這里也是私有的哦! }; void Base::virFunc(){ cout<<"Virtual function static defined in Base!"<<endl; } void Base::callVirFunc(){ virFunc();//調用Derived class中的實現版本 Base::virFunc();//調用Base class中的static版本 } void Derived::virFunc(){ cout<<"Virtual function defined in Derived!"<<endl; } int main(){ Base *pd = new Derived; pd->callVirFunc(); delete pd; return 0; }
運行結果:
:!./pure_virtual_func_test Virtual function defined in Derived! Virtual function static defined in Base!
例子中, Base class中的callVirFunc函數分別調用了在Base class中定義的純虛函數版本和Derived class中的實現版本。神奇吧!
其實這個例子是很特殊的哦!它還是反映了另外一個有趣的問題哦!注意!Base class中的callVirFunc函數調用了Derived class中的私有虛函數!它竟然繞過了訪問控制機制!對於這個問題,CSDN中的兄弟們進行了激烈的討論(在這里http://topic.csdn.net/t/20040805/16/3245820.html)。我想說的是,從編譯器的角度看,這是完全沒有問題的,因為當前對象的類類型是Derived,它的vptr指向Derived的虛函數表。還有一個問題就是,在虛函數表中並沒有訪問控制信息,所以此時調用虛函數的時候,拿到的當然就是Derived的版本並正確執行嘍。這種做法確實可以造成一些看起來詭異的程序行為,所以盡量避免這樣做吧。如果想讓程序更有序,更清晰,在虛函數中調用私有的本地函數是比較好的方式。