1. 程式人生 > >建構函式和解構函式及類中指標成員變數的new和delete

建構函式和解構函式及類中指標成員變數的new和delete

一直對於C++的繼承機制非常疑惑,今天專門研究了一下繼承過程中建構函式、虛構函式、以及對於建構函式初始化的一些問題。入的坑,還望大家少走彎路。

建構函式中new記憶體分配及解構函式delete

大家都知道,當程式中建立一個類指標物件並將其初始化的時候,只要該類有指標成員變數,且在建構函式中利用new操作符為該指標變數分配堆塊上的記憶體時,我們就需要實時注意需要手動管理該段記憶體的釋放。函式中用delete操作符對建立的類物件進行刪除和釋放類物件記憶體的時候,需要在解構函式函式體中對該指標成員變數所佔用的記憶體釋放掉,若是指標物件則用delete object,若是指標陣列,則用delete[] object。

但是有一個問題是,若是具有形參的建構函式對該類初始化的時候,在建構函式中不僅需要將為該指標成員變數分配記憶體,還需要將建構函式的傳參內容逐個複製到動態分配的記憶體中來。如下Base類及其原始碼實現:

class Base

{

public:

    Base(char *n);

    virtual ~Base();

private:

    char *name;

};

Base::Base(char*n)

{

    name = new char[20];

    strcpy(name,n);

    cout<<"Baseclass constructor..."<<endl

;

}

Base::~Base()

{

    delete[] name;

    cout<<"Baseclass destructor..."<<endl;

}

我們在Base類中定義了name指標變數,在Base建構函式中為name分配20個char型別的連續記憶體,並利用strcpy函式將建構函式傳參n逐字複製到name中,這是為什麼呢?為什麼不直接name=n,直接賦值,多省事?非也!

因為在函式中的區域性變數均是儲存在棧上的,我們知道棧上的記憶體在函式呼叫結束後,系統就自動將其記憶體釋放,name=n只是將n資料所在的記憶體地址告訴了name,建構函式呼叫結束後,棧上的n資料早已經被系統釋放了,再次呼叫解構函式對name所指的記憶體進行釋放就會釋放已經被釋放的棧上記憶體,就會出錯,便會出現_BLOCK_TYPE_IS_VALID(pHead->nBlockUse字樣的corruption,至於詳細解釋,請參考部落格(

_BLOCK_TYPE_IS_VALID(pHead->nBlockUse問題解析)。

虛解構函式bug

我們知道建構函式不能是虛擬函式,因為建構函式還沒實現的情況下是不能使用多型性的。而解構函式大多時候需要宣告為虛擬函式,若基類的解構函式不是虛擬函式,則當聲明瞭基類指標指向派生類物件釋放該指標時只會呼叫基類的解構函式,因此也只會釋放掉基類物件指向的記憶體部分,而解構函式宣告為virtual的話,則delete指標的時候,則會首先呼叫派生類的解構函式,接著呼叫基類的解構函式,完全釋放掉該指標物件所指向記憶體。