在實習的單位搞CxImage庫時不知為什麼在Debug時沒有問題,但是Release版裡竟然跳出個Pure virtual function call error! 啥東西呀,竟然遇上了,就探個究竟吧!
MSDN上的解釋
http://forums.msdn.microsoft.com/zh-CN/clr/thread/bfa759a8-0cc0-4d65-8711-d2d0d6765687/
這時講得很詳細
http://www.artima.com/cppsource/pure_virtual.html
看看Codeproject上的一個例子
http://www.codeproject.com/KB/cpp/PureVirtualFunctionCall.aspx
(1)出現 Pure virtual function call 的原因是:
the child destructor is called and finished, so, we don’t have an object of type child now, but the current object (which is only being destructed) is of type Parent, so all calls in the destructor are calls to functions in this object. So, you can get a pure virtual function.
繼承類的對象析構被調用,而且完成了釋放,那麼現在這個對象就不存在了,但是當前的對象(正在釋構的父類對象)卻要調用其子類的虛函數實現(因為自身是純虛函數),所以就會出現Pure virtual function call error!
(2) 由物件導向的概念知,對象的析構是子類先析構再到父類析構,所以如果在父類中要調用自身的虛純數將會很危險了,而且在是運行時出現的。
以下是codeproject的例子
Class Parent{public: Parent() { } ~Parent() { ClearALL(); } void ClearALL() { ThePure(); //調用自身的純虛函數,封裝一下是因為直接調用編譯器會識別出這樣調用是有問題的!} virtual bool ThePure() = 0 ;}; class Child : public Parent{public: Child() { } ~Child() { } //The implementation of the pure virtual function virtual bool ThePure() { return true; } }; void main(){ Child c;}
當C析構時,虛函數表裡的 ThePure() 已經登出,那麼父類 Parent 裡的ClearALL() 裡的ThePure() 虛表指標就會指向一個空地址(成了 dangling pointer 了), 所以在Parent裡調用 ClearALL() 就會出錯了
(3)如果上面的情況還算直觀的話,看看下面的一種造成 pure virtual function call的情況就更隱蔽了。
//不過我在VC6裡沒有問題class Base {public: virtual void function() = 0;};class B : public Base{public: virtual void function() { cout<<"pure function call in B"<<endl; }};class A {public: A(B* b):_b(b) {} ~A() { _b->function(); } B* _b;};B b;a(&b);int main(){ return 0;}
這種情況在某些編譯器下會出pure virtual function call錯誤。主要的原因是因為全域變數的釋放順序不確定,全域變數A依賴全域變數B。如果編譯器決定讓B先釋放,A後釋放。那麼,當A析構時,_b是一個dangling pointer。此時如果b對象的記憶體系統沒有釋放的話,那麼b的vptr表指向的是Base的vptr,而不是B的。此時,_b->function()就指向了pure virtual function了。詳細情況可以到看看
http://www.cnblogs.com/whjiang/archive/2007/10/22/932880.html
(5)論壇上關於出現pure virtual function call 的情況總結:
1. 基類構造器直接調用虛函數
2. 基類析構器直接調用虛函數
3. 基類構造器間接調用虛函數
4. 基類析構器間接調用虛函數
5. Calling a virtual function via a dangling pointer.
(4)為了在遇到 pure virtual function call 時不致於程式蹦掉,可以實現在一基類的純虛函數,但要記住找出原因後要刪掉實現的代碼