[轉載] 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