【轉】c++析構函數(Destructor)

建立對象時系統會自動調用構造函數進行初始化工做,一樣,銷燬對象時系統也會自動調用一個函數來進行清理工做,例如釋放分配的內存、關閉打開的文件等,這個函數就是析構函數。

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

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

上節咱們定義了一個 VLA 類來模擬變長數組,它使用一個構造函數爲數組分配內存,這些內存在數組被銷燬後不會自動釋放,因此很是有必要再添加一個析構函數,專門用來釋放已經分配的內存。請看下面的完整示例:
html

 

#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。
ios

析構函數的執行時機

析構函數在對象被銷燬時調用,而對象的銷燬時機與它所在的內存區域有關。不瞭解內存分區的讀者請閱讀《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
數組

 

 

本帖原文地址:函數

http://c.biancheng.net/cpp/biancheng/view/196.htmlspa

相關文章
相關標籤/搜索