1. 程式人生 > 實用技巧 >[轉載] C++解構函式

[轉載] C++解構函式

轉載於C語言中文網,C++解構函式(Destructor)

建立物件時系統會自動呼叫建構函式進行初始化工作,同樣,銷燬物件時系統也會自動呼叫一個函式來進行清理工作,例如釋放分配的記憶體、關閉開啟的檔案等,這個函式就是解構函式。

解構函式(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。

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

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

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

解構函式的執行時機

解構函式在物件被銷燬時呼叫,而物件的銷燬時機與它所在的記憶體區域有關。

在所有函式之外建立的物件是全域性物件,它和全域性變數類似,位於記憶體分割槽中的全域性資料區,程式在結束執行時會呼叫這些物件的解構函式。

在函式內部建立的物件是區域性物件,它和區域性變數類似,位於棧區,函式執行結束時會呼叫這些物件的解構函式。

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