C++中基類的析構函數不是虛函數,會帶來什么問題!!


如下例:

#include <iostream>
using namespace std;

class Father
{
public:
    Father(){cout<<"contructor Father!"<<endl;};
    ~Father(){cout<<"destructor Father!"<<endl;};
};

class Son:public Father
{
public:
    Son(){cout<<"contructor Son!"<<endl;};
    ~Son(){cout<<"destructor Son!"<<endl;};
};

int main()
{
    Father *pfather=new Son;
    delete pfather;
    pfather=NULL;

    return 0;
}

  

運行結果:

contructor Father!
contructor Son!
destructor Father!

(1)基類的的析構函數不是虛函數的話,刪除指針時,只有其類的內存被釋放,派生類的沒有。這樣就內存泄漏了。

(2)析構函數不是虛函數的話,直接按指針類型調用該類型的析構函數代碼,因為指針類型是基類,所以直接調用基類析構函數代碼。

(3)delete是刪除指針p指向的實例,p指針本身依然存在,delete后將p置為空值是常用做法,空值一般寫成NULL宏,其實就是0。因為內存0位置是不允許訪問的,delete 0操作編譯器可以判斷是錯誤操作不會執行,因此將p置為空值0是很安全的做法。

(4)當基類指針指向派生類的時候,如果析構函數不聲明為虛函數,在析構的時候,不會調用派生類的析構函數,從而導致內存泄露。

(5)子類對象創建時先調用父類構造函數然后在調用子類構造函數,在清除對象時順序相反,所以delete p只清除了父類,而子類沒有清除

總結:

(1) 對於這個程序,實際上是沒有關系的,delete pfather雖然只調用了Father類的析構函數,但是程序運行完成,退出main函數后,Son類的部分數據也會被自動清除。
(2) 那么什么時候才要用虛析構函數呢?通常情況下,程序員的經驗是,當類中存在虛函數時要把析構函數寫成virtual,因為類中存在虛函數,就說明它有想要讓基類指針或引用指向派生類對象的情況,
此時如果派生類的構造函數中有用new動態產生的內存,那么在其析構函數中務必要delete這個數據,但是一般的像以上這種程序,這種操作只調用了基類的析構函數,而標記成虛析構函數的話,系統會先
調用派生類的析構函數,再調用基類本身的析構函數。
(3)一般情況下,在類中有指針成員的時候要寫copy構造函數,賦值操作符重載和析構函數。

修改后:
#include <iostream>
using namespace std;

class Father
{
public:
    Father(){cout<<"contructor Father!"<<endl;};
    virtual ~Father(){cout<<"destructor Father!"<<endl;};
};

class Son:public Father
{
public:
    Son(){cout<<"contructor Son!"<<endl;};
    ~Son(){cout<<"destructor Son!"<<endl;};
};

int main()
{
    Father *pfather=new Son;
    delete pfather;
    pfather=NULL;

    return 0;
}

結果:

contructor Father!
contructor Son!
destructor Son!
destructor Father!




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM