天天看點

關于拷貝構造函數

首先不要使用VC編譯器來測試,看看這段代碼并猜想它會調用幾次構造函數和析構函數,最後再測試一下:

#include <iostream.h>

class A

{

public:

A()

{

cout<<"Construction..."<<endl;

}

~A()

cout<<"Destruction...."<<endl;

};

A foo(A a)

return a;

}

int main(int argc, char* argv[])

A a;

foo(a);

A b = foo(a);

return 0;

在VC編譯運作後結果大失所望吧?不明白不要緊,VC這個內建的IDE開發工具它的“博大精深”值得我們慢慢學習與積累,先看看下面我查找的資料吧:

一、拷貝構造函數

  拷貝構造函數,是一種特殊的構造函數,它由編譯器調用來完成一些基于同一類的其他對象的建構及初始化。其唯一的參數(對象的引用)是不可變的(const類型)。此函數經常用在函數調用時使用者定義類型的值傳遞及傳回。拷貝構造函數要調用基類的拷貝構造函數和成員函數。如果可以的話,它将用常量方式調用,另外,也可以用非常量方式調用。

  在C++中,下面三種對象需要調用拷貝構造函數:

  1) 一個對象以值傳遞的方式傳入函數體;

  2) 一個對象以值傳遞的方式從函數傳回;

  3) 一個對象需要通過另外一個對象進行初始化;

  如果在前兩種情況不使用拷貝構造函數的時候,就會導緻一個指針指向已經被删除的記憶體空間。對于第三種情況來說,初始化和指派的不同含義是構造函數調用的原因。事實上, 拷貝構造函數是由普通構造函數和指派操作符共同實作的。描述拷貝構造函數和指派運算符的異同的參考資料有很多。

  拷貝構造函數不可以改變它所引用的對象,其原因如下:當一個對象以傳遞值的方式傳一個函數的時候,拷貝構造函數自動的被調用來生成函數中的對象。如果一個對象是被傳入自己的拷貝構造函數,它的拷貝構造函數将會被調用來拷貝這個對象這樣複制才可以傳入它自己的拷貝構造函數,這會導緻無限循環直至棧溢出(Stack Overflow)。除了當對象傳入函數的時候被隐式調用以外,拷貝構造函數在對象被函數傳回的時候也同樣的被調用。

   如果在類中沒有顯式的聲明一個拷貝構造函數,那麼,編譯器會自動生成一個來進行對象之間的位拷貝(Bitwise Copy)。這個隐含的拷貝構造函數簡單的關聯了所有的類成員。注意到這個隐式的拷貝構造函數和顯式聲明的拷貝構造函數的不同在于對成員的關聯方式。顯式聲明的拷貝構造函數關聯的隻是被執行個體化的類成員的預設構造函數,除非另外一個構造函數在類初始化或構造清單的時候被調用。

  拷貝構造函數使程式更有效率,因為它不用再構造一個對象的時候改變構造函數的參數清單。設計拷貝構造函數是一個良好的風格,即使是編譯系統會自動為你生成預設拷貝構造函數。事實上,預設拷貝構造函數可以應付許多情況。

上述開篇的那段代碼,因為它并不隻是唯一的一個構造函數(實際上調用了四次拷貝構造函數),是以你可以顯式的聲明一個拷貝構造函數再編譯試試,代碼如下:

// 預設構造函數(這時編譯器不會再提供構造函數給你)

// 拷貝構造函數

A(const A & a)

cout<<"Copy Construction..."<<endl;

// 重載等于操作符

A & operator=(const A & a)

cout<<"Assignment operator..."<<endl;

// 預設析構函數

二、程式運作效果:

關于拷貝構造函數

三、參考資料:

Cedric Moonen

Pallini