拷貝構造函數與賦值構造函數

A(const A&);   //默認拷貝構造函數

A& operater = (const A& a);   //默認賦值函數

【弊端】:若類中包含指針成員或引用成員,這兩個默認的函數可能隱含錯誤。

(1)   原有的內存沒有釋放,造成內存泄漏;

(2)   使兩個對象中的指針成員指向同一塊內存,任何一方變動都會影響另一方;

(3)   在對象析構時,delete兩次。

 

拷貝構造函數:在創建對象,並用另一個已經存在的對象來初始化它時調用。

如:String a("hello");   //調用帶參數的構造函數

       String b(a);   //或是String b = a,調用拷貝構造函數

賦值函數:把一個對象賦值給另一個已經存在的對象,使得已經存在的那個對象和源對象具有相同的狀態。

如:String c;

        c = a;

 

類String拷貝構造函數在函數入口處不用與NULL比較,因爲引用不可能是NULL,而指針可以爲NULL,所以在默認構造函數中需與NULL比較。

例1:類String的拷貝構造函數和拷貝賦值函數

String::String(const String& other)

{

    int length = strlen(other.m_data);

m_data = new char[length + 1];

    strcpy(m_data, other.m_data);

m_size = length;

}

 

String& String::operator = (const String& other)

{

//(1)檢查自賦值

if (this != &other)  //地址相等才認爲是同一對象,不能錯寫成if (*this = other)

{

//(2)分配新的內存空間,並拷貝內容

char* temp = new char[strlen(other.m_data) + 1];

strcpy(temp, other.m_data );  //連'/0'一起拷貝

//(3)釋放原有的內存資源

delete [ ] m_data;

m_data = temp;

m_size = strlen(other.m_data);

}

//(4)返回本對象的引用

return *this;  //返回本對象的引用,目的是爲了實現a=b=c這樣的鏈式表達式

}

如果先把原有的內存釋放,如果後來內存重分配失敗,就慘了!所以,先分配內存給一個臨時指針,萬一分配失敗也不會改變this對象。

 

如果我們不想編寫拷貝構造函數和拷貝賦值函數(不想拷貝對象),又不允許使用編譯器自動生成的默認函數,只需將拷貝構造函數和拷貝賦值函數聲明爲private,並且不實現它們。

 

基類的構造函數、析構函數和賦值函數不能被派生類繼承。如果存在類繼承關係,則在編寫基本函數時應該注意:

(1)   派生類的構造函數應該其初始化列表裏顯式地調用基類構造函數;

(2)   如果基類是多態類(包括虛函數的類),則必須把基類的析構函數定義爲虛函數,這樣可以像其他函數一樣實現動態綁定,否則可能會造成內存泄漏;

如:Base *pB = new Derived;

     是虛函數,析構時先調用Derived::~Derived(),再調用Base::~Base()

     不是虛函數,則直接調用Base::~Base(),因此派生類對象的內存不會釋放,造成內存泄漏

(3)   在編寫派生類的賦值函數時,要記得對基類的數據成員重新賦值,可以通過調用基類的賦值函數來實現。

如:

Derived& Derived::operater = (const Derived& other)

{

//(1)檢查自賦值

if (this != &other)

{

//(2)對基類的數據成員重新賦值

Base::operator = (other);

//(3)對派生類的數據成員賦值

m_x = other.m_x;

m_y = other.m_y;

m_z = other.m_z;

}

//(4)返回本對象的引用

return *this;

}

------------------------

 

文章轉自互聯網。。。

發佈了45 篇原創文章 · 獲贊 3 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章