程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 再說c++虛析構函數

再說c++虛析構函數

編輯:關於C++

關於c++類中的虛析構函數。我得出如下3點結論

1.所有基類的析構函數,都應該聲明為虛析構函數!這也是c++標准所指定的。
2.如果設計一個類,可能會被後來的其他類所繼承,我們一定要將它的析構函數聲明為虛析構。否則被繼承會出現內存洩漏等意想不到的問題。
3.如果我們要去繼承另外一個類,首先一點是要保證被繼承的類的析構函數已經聲明為了虛析構函數!
對以上3點,如果你深有理會,如下內容可以不看,不要浪費時間。如果沒有很深的概念,可以參考一下。如有問題,希望在評論區或其他方式給我指點,謝謝。

 

非繼承類的析構函數執行會有如下操作

1、執行析構函數中的代碼

2、如果所在類有成員變量(類對象),再執行類成員變量的析構函數

普通析構函數:

以如下代碼為例

 



class Student
{
public:
    Student()
    {
        name = new char[32];
        cout << "Student constructor new name char[32]" << endl;
    }
    ~Student()
    {
        delete name;
        cout << "Student destructor delete Student::name" << endl;
    }

private:
    char* name;
};

class Normal
{
public:
    Student stu;
    Normal(){cout << "Normal constructor" << endl;}
    ~Normal(){cout << "Normal destructor" << endl;}
};

int main()
{
    Normal* pn = new Normal();
    delete pn;
    return 0;
}
執行結果:

\

 


(表示很討厭上面的水印)

 

 

析構順序:

1、執行析構函數中的代碼

2、如果所在類有成員變量(類對象),再執行類成員變量的析構函數


\

以上內容很好理解,因為只是單個類對象的析構,當然也關系到類的組合。
接下來我想討論的是存在繼承關系時,析構函數在做些什麼?


#include 
using namespace std;
#include 

class Student
{
public:
    Student()
    {
        name = new char[32];
        cout << "Student constructor new name char[32]" << endl;
    }
    ~Student()
    {
        delete []name;
        cout << "Student destructor delete Student::name" << endl;
    }

private:
    char* name;
};


class Base
{
public:
    Base()
    {
        cout << "Base()" << endl;
    }

    ~Base()
    {
        cout << "~Base()" << endl;
    }
};
class Derived:public Base
{
public:
    Derived()
    {
        cout << "Derived()" << endl;
    }
    ~Derived()
    {
        cout << "~Derived()" << endl;
    }

    Student stu;
};
int main()
{
    Derived *pd = new Derived();
    delete pd;
    return 0;
}
執行結果:

\


派生類對象的析構過程:
1,調用派生類對象的析構函數,
2,調用派生類中成員對象的析構函數
3,調用基類的析構函數

\

-------------------------------------我是丑陋的分割線-------------------------------------------

在分割線的上方,一切正常,沒有什麼特別的,異樣的地方。
接下來要討論的是多態情況下的析構函數。

#include 
using namespace std;
#include 

class Student
{
public:
    Student()
    {
        name = new char[32];
        cout << "Student constructor new name char[32]" << endl;
    }
    ~Student()
    {
        delete []name;
        cout << "Student destructor delete Student::name" << endl;
    }

private:
    char* name;
};


class Base
{
public:
    Base()
    {
        cout << "Base()" << endl;
    }

    ~Base()
    {
        cout << "~Base()" << endl;
    }
};
class Derived:public Base
{
public:
    Derived()
    {
        cout << "Derived()" << endl;
    }
    ~Derived()
    {
        cout << "~Derived()" << endl;
    }

    Student stu;
};
int main()
{
    Base* pb = new Derived(); // 注意這一行,基類指針指向了派生類
    delete pb;  	      // delete 基類指針
    return 0;
}

執行結果:

\

\
只調用基類的析構函數,派生類的析構函數沒有被調用,更要注意的是,因此派生類的成員對象也沒有被析構,缺少了“Student destructor delete Student::name”
所以會有內存洩漏。
如下代碼也會出現內存洩漏:

class Base
{
};
class Derived:public Base
{
public:
    string str; // 這種內存洩漏就不容易發現了!!!
};
int main()
{
    Base* pb = new Derived(); // 派生類的string對象會發生內存洩漏!
    delete pb;
    return 0;
}
如上類繼承時發生的內存洩漏,如何解決?
只需要將基類的析構函數聲明為虛析構函數,就是前面加上virtual.

#include 
using namespace std;
#include 

class Student
{
public:
    Student()
    {
        name = new char[32];
        cout << "Student constructor new name char[32]" << endl;
    }
    ~Student()
    {
        delete []name;
        cout << "Student destructor delete Student::name" << endl;
    }

private:
    char* name;
};


class Base
{
public:
    Base()
    {
        cout << "Base()" << endl;
    }

    virtual ~Base()
    {
        cout << "~Base()" << endl;
    }
};
class Derived:public Base
{
public:
    Derived()
    {
        cout << "Derived()" << endl;
    }
    ~Derived()
    {
        cout << "~Derived()" << endl;
    }

    Student stu;
};
int main()
{
    Base* pb = new Derived();
    delete pb;
    return 0;
}


\運行結果:

\\ 發現一切OK了。


總結:
1.所有基類的析構函數,都應該聲明為虛析構函數!這也是c++標准所指定的。
2.如果設計一個類,可能會被後來的其他類所繼承,我們一定要將它的析構函數聲明為虛析構。否則被繼承會出現內存洩漏等意想不到的問題。
3.如果我們要去繼承另外一個類,首先一點是要保證被繼承的類的析構函數已經聲明為了虛析構函數!



 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved