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

C++析構函數(Destructor)

編輯:C++基礎知識
創建對象時系統會自動調用構造函數進行初始化工作,同樣,銷毀對象時系統也會自動調用一個函數來進行清理工作,例如釋放分配的內存、關閉打開的文件等,這個函數就是析構函數。

析構函數(Destructor)也是一種特殊的成員函數,沒有返回值,不需要程序員顯式調用(程序員也沒法顯式調用),而是在銷毀對象時自動執行。構造函數的名字和類名相同,而析構函數的名字是在類名前面加一個~符號。

注意:析構函數沒有參數,不能被重載,因此一個類只能有一個析構函數。如果用戶沒有定義,編譯器會自動生成一個默認的析構函數。

上節我們定義了一個 VLA 類來模擬變長數組,它使用一個構造函數為數組分配內存,這些內存在數組被銷毀後不會自動釋放,所以非常有必要再添加一個析構函數,專門用來釋放已經分配的內存。請看下面的完整示例:
#include <iostream>
using namespace std;

class VLA{
public:
    VLA(int len);  //構造函數
    ~VLA();  //析構函數
public:
    void input();  //從控制台輸入數組元素
    void show();  //顯示數組元素
private:
    int *at(int i);  //獲取第i個元素的指針
private:
    const int m_len;  //數組長度
    int *m_arr; //數組指針
    int *m_p;  //指向數組第i個元素的指針
};

VLA::VLA(int len): m_len(len){
    if(len > 0){ m_arr = new int[len];  /*分配內存*/ }
    else{ m_arr = NULL; }
}
VLA::~VLA(){
    delete[] m_arr;  //釋放內存
}
void VLA::input(){
    for(int i=0; m_p=at(i); i++){ cin>>*at(i); }
}
void VLA::show(){
    for(int i=0; m_p=at(i); i++){
        if(i == m_len - 1){ cout<<*at(i)<<endl; }
        else{ cout<<*at(i)<<", "; }
    }
}
int * VLA::at(int i){
    if(!m_arr || i<0 || i>=m_len){ return NULL; }
    else{ return m_arr + i; }
}

int main(){
    //創建一個有n個元素的數組(對象)
    int n;
    cout<<"Input array length: ";
    cin>>n;
    VLA *parr = new VLA(n);
    //輸入數組元素
    cout<<"Input "<<n<<" numbers: ";
    parr -> input();
    //輸出數組元素
    cout<<"Elements: ";
    parr -> show();
    //刪除數組(對象)
    delete parr;

    return 0;
}
運行結果:
Input array length: 5
Input 5 numbers: 99 23 45 10 100
Elements: 99, 23, 45, 10, 100

~VLA()就是 VLA 類的析構函數,它的唯一作用就是在刪除對象(第 53 行代碼)後釋放已經分配的內存。

函數名是標識符的一種,原則上標識符的命名中不允許出現~符號,在析構函數的名字中出現的~可以認為是一種特殊情況,目的是為了和構造函數的名字加以對比和區分。

注意:at() 函數只在類的內部使用,所以將它聲明為 private 屬性;m_len 變量不允許修改,所以用 const 限制。

C++ 中的 new 和 delete 分別用來分配和釋放內存,它們與C語言中 malloc()、free() 最大的一個不同之處在於:用 new 分配內存時會調用構造函數,用 delete 釋放內存時會調用析構函數。構造函數和析構函數對於類來說是不可或缺的,所以在C++中我們非常鼓勵使用 new 和 delete。

析構函數的執行時機

析構函數在對象被銷毀時調用,而對象的銷毀時機與它所在的內存區域有關。不了解內存分區的讀者請閱讀《C語言和內存》專題。

在所有函數之外創建的對象是全局對象,它和全局變量類似,位於內存分區中的全局數據區,程序在結束執行時會調用這些對象的析構函數。

在函數內部創建的對象是局部對象,它和局部變量類似,位於棧區,函數執行結束時會調用這些對象的析構函數。

new 創建的對象位於堆區,通過 delete 刪除時才會調用析構函數;如果沒有 delete,析構函數就不會被執行。

下面的例子演示了析構函數的執行。
#include <iostream>
#include <string>
using namespace std;

class Demo{
public:
    Demo(string s);
    ~Demo();
private:
    string m_s;
};
Demo::Demo(string s): m_s(s){ }
Demo::~Demo(){ cout<<m_s<<endl; }

void func(){
    //局部對象
    Demo obj1("1");
}

//全局對象
Demo obj2("2");

int main(){
    //局部對象
    Demo obj3("3");
    //new創建的對象
    Demo *pobj4 = new Demo("4");
    func();
    cout<<"main"<<endl;
  
    return 0;
}
運行結果:
1
main
3
2
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved