C++虛析構函數解析,函數解析
當派生類對象從內存中撤銷時一般先運行派生類的析構函數,然後再調用基類的析構函數。
如果用new運算符建立的派生類的臨時對象,對指向基類的指針指向這個臨時對象當用delete運算符撤銷對象時,系統執行的是基類的析構函數,而不是派生類的析構函數,不能徹底的“清理現場”。解決的方法是將基類及派生類的析構函數設為虛函數,這時無論基類指針指向哪個派生類對象,系統會采用動態關聯,調用相應的析構函數對對象進行清理。
class Point
{
public :
Point(){};
~Point(){ std::cout << "Point destructor" << std::endl; }
private :
};
class Circle: public Point
{
public :
Circle(){};
~Circle(){ std::cout << "Circle destructor" << std::endl; };
private :
};
int _tmain( int argc , _TCHAR* argv[])
{
Point *p = new Circle;
delete p;
getchar();
return 0;
}
程序運行結果如下:
下面將基類的析構函數改成虛析構函數
virtual ~Point(){ std::cout << "Point destructor" << std::endl; }
其它的不變,再運行:
這樣就達到我們的目的了,基類,派生類都調用了析構函數,另外需要注意的是
在基類的析構函數聲明為虛函數時,由該基類派生的析構函數也自動成為虛函數,即使派生類的析構函數與基類的析構函數名字不相同。
程序中顯示的用delete運算符刪除一個對象,而這個對象是指向派生類對象的基類指針,系統調用相應派生類的析構函數。
如果程序中的局部對象離開其作用域,系統會隱式地調用其析構函數
咱們增加一個函數並從寫main函數:
Point *fc()
{
Circle cl;
Point *p = new Circle;
return p;
}
int _tmain( int argc , _TCHAR* argv[])
{
Point *q = fc();
delete q;
getchar();
return 0;
}
運行結果如下:
在上例中,函數非常fc的內部定義了兩個對象:c1和p所指向的Circle類對象。對象cl在函數fc結束時執行Circle的析構函數,撤銷局部變量c1.p所指向的對象的地址通過函數返回值賦予q,q所指向的對象在執行delete時執行析構函數。
對於虛析構函數的調用問題
虛函數存放在類的虛表中,虛函數的調用如果不是顯示調用的話,默認是調用子類的虛函數。
當基類的析構函數是虛函數的時候,子類繼承基類的虛函數,所以子類的析構函數也是虛函數。
如上面的例子,雖然new CExtend賦值給了CBase *PBase,但當調用delete pBase時,由於虛函數的動態關聯,首先調用的是子類中的析構函數。當子類析構函數執行完畢後,子類所占用的內存,相對於父類多出的內存就已經得到完全釋放了(注:子類的析構函數結束之前完成了子類自己的資源的釋放)。此時,子類被釋放了,就不會再有子類存在了,所以將會繼續調用基類中的析構函數,來繼續執行。
而當析構函數不是虛函數的時候,就不會有動態關聯的功能。由於pBase的類型是CBase,所以就相當於顯示調用了基類中的CBase的析構函數,而子類中的析構函數卻沒有被調用,如果自類中有自己的在“堆”上開辟的空間的話,而恰好是在子類的析構函數中完成內存回收的話,這樣就會因為沒有執行到子類的析構函數,而導致內存洩漏。
然而,對於子類中沒有任何在“堆”上申請的空間的話,析構函數是否為虛函數,都將不會產生內存洩漏。
對於虛析構函數與一般虛函數,以下說法正確的是
重定義函數好比是單獨的在基類和派生類中各自定義了一個方法,相互之間沒有聯系。
如: fun()函數在A類和B類中都有,A是基類,B從A派生來的。那麼派生類的對象交給他的父類的指針時,指針調用只能調用到父類的函數。
A a;
B b;
A *c= new B;
a.fun 調用A類的fun,b.fun調用B類的fun,c->fun 調用A類的fun
構造函數是沒有虛不虛這一說的。
析構函數被申明為虛,是為了解決基類的指針指向派生類對象,並用基類的指針刪除派生類對象。虛析構函數工作的方式是:最底層的派生類的析構函數最先被調用,然後各個基類的析構函數被調用。
虛函數的作用是實現動態聯編,也就是在程序的運行階段動態地選擇合適的成員函數,在定義了虛函數後,可以在基類的派生類中對虛函數重新定義,在派生類中重新定義的函數應與虛函數具有相同的形參個數和形參類型。以實現統一的接口,不同定義過程。如果在派生類中沒有對虛函數重新定義,則它繼承其基類的虛函數。
我覺得答案應該是 C