1-什麼時候會用到拷貝建構函式?
當任何你想影印東西的時候,而不管東西被影印成什麼樣子。即任何你想利用乙個已有的類例項給另乙個類例項賦值時,這種賦值可能是顯式的,也可能是隱式的
顯式:classa_1=class_2;
隱式:函式的形參有用到類物件卻沒有用引用或傳址技術時
函式的返回值是乙個物件也沒有應用傳址技術時
2- 什麼是拷貝建構函式?
int a = 10;
int b =a;
自己定義的類的物件同樣是物件,誰也不能阻止我們用以下的方式進行複製,例如:
#include
using
namespace std;
class test
protected:
int p1;
};
void
main()
普通物件和類物件同為物件,他們之間的特性有相似之處也有不同之處,類物件內部存在成員變數,而普通物件是沒有的,當同樣的複製方法發生在不同的物件上的時候,那麼系統對他們進行的操作也是不一樣的,就類物件而言,相同型別的類物件是通過拷貝建構函式來完成整個複製過程的,在上面的**中,我們並沒有看到拷貝建構函式,同樣完成了複製工作,這又是為什麼呢?因為當乙個類沒有自定義的拷貝建構函式的時候系統會自動提供乙個預設的拷貝建構函式,來完成複製工作。
下面,我們為了說明情況,就普通情況而言(以上面的**為例),我們來自己定義乙個與系統預設拷貝建構函式一樣的拷貝建構函式,看看它的內部是如何工作的!
**如下:
#include
using
namespace std;
class test
test(test &c_t)//這裡就是自定義的拷貝建構函式
public:
int p1;
};
void
main()
上面**中的test(test &c_t)就是我們自定義的拷貝建構函式,拷貝建構函式的名稱必須與類名稱一致,函式的形式引數是本型別的乙個引用變數,且必須是引用。
當用乙個已經初始化過了的自定義類型別物件去初始化另乙個新構造的物件的時候,拷貝建構函式就會被自動呼叫,如果你沒有自定義拷貝建構函式的時候系統將會提供給乙個預設的拷貝建構函式來完成這個過程,上面**的複製核心語句就是通過test(test &c_t)拷貝建構函式內的p1=c_t.p1;語句完成的。如果取掉這句**,那麼b物件的p1屬性將得到乙個未知的隨機值;
下面我們來討論一下關於淺拷貝和深拷貝的問題。
就上面的**情況而言,很多人會問到,既然系統會自動提供乙個預設的拷貝建構函式來處理複製,那麼我們沒有意義要去自定義拷貝建構函式呀,對,就普通情況而言這的確是沒有必要的,但在某寫狀況下,類體內的成員是需要開闢動態開闢堆記憶體的,如果我們不自定義拷貝建構函式而讓系統自己處理,那麼就會導致堆記憶體的所屬權產生混亂,試想一下,已經開闢的一端堆位址原來是屬於物件a的,由於複製過程發生,b物件取得是a已經開闢的堆位址,一旦程式產生析構,釋放堆的時候,計算機是不可能清楚這段位址是真正屬於誰的,當連續發生兩次析構的時候就出現了執行錯誤。
為了更詳細的說明問題,請看如下的**。
#include
using
namespace std;
class internet
} internet(internet &temp)
} ~internet()
void show();
protected:
char name[20];
char address[30];
char *cname;
};
void internet::show()
上面**就演示了深拷貝的問題,對物件b的cname屬性採取了新開闢記憶體的方式避免了記憶體歸屬不清所導致析構釋放空間時候的錯誤,最後我必須提一下,對於上面的程式我的解釋並不多,就是希望讀者本身執行程式觀察變化,進而深刻理解。
拷貝和淺拷貝的定義可以簡單理解成:如果乙個類擁有資源(堆,或者是其它系統資源),當這個類的物件發生複製過程的時候,這個過程就可以叫做深拷貝,反之物件存在資源但複製過程並未複製資源的情況視為淺拷貝。
淺拷貝資源後在釋放資源的時候會產生資源歸屬不清的情況導致程式執行出錯,這點尤其需要注意!
以前我們的教程中討論過函式返回物件產生臨時變數的問題,接下來我們來看一下在函式中返回自定義型別物件是否也遵循此規則產生臨時物件!
先執行下列**:
#include
using
namespace std;
class internet
; internet(char *name,char *address)
~internet()
protected:
char name[20];
char address[20];
};
internet tp()
void
main()
從上面的**執行結果可以看出,程式一共載入過析構函式三次,證明了由函式返回自定義型別物件同樣會產生臨時變數,事實上物件a得到的就是這個臨時internet類型別物件temp的值。
這下節的內容我們來說一下無名物件。
利用無名物件初始化物件系統不會呼叫拷貝建構函式。
那麼什麼又是無名物件呢?
很簡單,如果在上面程式的main函式中有:
internet ("中國軟體開發實驗室","www.***ev-lab.com");
這樣的一句語句就會產生乙個無名物件,無名物件會呼叫建構函式但利用無名物件初始化物件系統不會呼叫拷貝建構函式!
下面三段**是很見到的三種利用無名物件初始化物件的例子。
#include
using
namespace std;
class internet
~internet()
public:
char name[20];
char address[20];
};
void
main()
上面**的執行結果有點「出人意料」,從思維邏輯上說,當無名物件建立了後,是應該呼叫自定義拷貝建構函式,或者是預設拷貝建構函式來完成複製過程的,但事實上系統並沒有這麼做,因為無名物件使用過後在整個程式中就失去了作用,對於這種情況c++會把**看成是:
internet a("中國軟體開發實驗室",www.***ev-lab.com);
省略了建立無名物件這一過程,所以說不會呼叫拷貝建構函式。
最後讓我們來看看引用無名物件的情況。
#include
using
namespace std;
class internet
~internet()
public:
char name[20];
char address[20];
};
void
main()
引用本身是物件的別名,和複製並沒有關係,所以不會呼叫拷貝建構函式,但要注意的是,在c++看來:
internet &a=internet("中國軟體開發實驗室","www.***ev-lab.com");
是等價與:
internet a("中國軟體開發實驗室","www.***ev-lab.com");
的,注意觀察呼叫析構函式的位置(這種情況是在main()外呼叫,而無名物件本身是在main()內析構的)。
**自:http://www.pconline.com.cn/pcedu/empolder/gj/c/0503/570112.html
C 建構函式 拷貝建構函式
建構函式 class base private int m var 建構函式無返回值型別,函式名和型別相同。拷貝建構函式傳遞引數為引用。1 class base2 7 拷貝建構函式 8 base base ref m var ref m var 9 11 private 12 intm var 13...
C 拷貝建構函式
1 拷貝構造 copy建構函式用於將乙個物件拷貝到新建立的物件中。也就是說它用於初始化過程中,而不是常規的賦值過程中。一般的copy建構函式原型通常如下 class name const class name rhs 它接受乙個指向類物件的常量引用作為引數。例如,cstring類的拷貝建構函式的原型...
C 拷貝建構函式
在基本資料型別的初始化中,如 int a b 編譯器只要將b的值作為a的初始值。假設我們已定義型別test,且有乙個已經初始化的test型物件x,如果我們希望定義乙個新的test型物件y,並且將x的值作為y的初始值,可以使用下面的語句 test y x 或者 test y x 上述語句均是合法的,它...