編譯器提供乙個不接受任何引數,也不執行任何操作的建構函式,稱之為預設建構函式
這是因為創造物件的時候總會呼叫預設建構函式
如果定義了建構函式,c++不會定義預設建構函式,如果希望建立物件時不顯示地對他進行初始化,則必須顯示的定義預設建構函式,這種預設的建構函式沒有任何引數,但是可以用來設定特定的值,比如說:klunk::klunk() {} //定義
klunk lunk; //宣告 使用預設建構函式
帶引數的建構函式也可以是預設建構函式,只要所有的引數都有預設值klunk::klunk(int n = 0)klunk::klunk()
但是注意,下面兩種建構函式不能共同宣告,會引起歧義
klunk::klunk(int n = 0)
klunk::klunk()
kulnk kar (10); //這回選擇只用第一種
kulnk bus; //兩種都可以,所以會報錯
上面這句話是常見的一種物件宣告方式,這種物件方式使用了哪種建構函式呢?不是預設建構函式,也不是 stringbad ::stringbad (const char *)這種建構函式,而是等效於下面這句話// 物件的宣告
stringbad sailor =sports
stringbad sailor =stringbad (sports)
因為sports的型別為stringbad ,所以說此時建構函式的原型如下
stringbad (const stringbad &)
當使用乙個物件初始化另乙個物件的時候,編譯器會自動生成建構函式,成為複製建構函式複製建構函式用於將乙個物件複製到新建立的物件中。也就是說,它用於初始化過程中(包括按值傳遞引數),而不是常規的複製過程,累的複製建構函式原型:
stringbad (const class_name &) // 他接受乙個指向類的物件的常量引用作為引數
何時呼叫複製建構函式新建乙個物件,並將其初始化為同類現有物件的時候,複製建構函式就會被呼叫,在很多情況下都可能發生,最常見的情況是將新物件顯示的初始化為現有的物件。
其中中間兩種的宣告可能會使用複製建構函式直接建立metto 和 also,也可能會生成乙個臨時物件,然後將臨時兌現的內容賦值給metto 和also。最後一種是初始化乙個匿名物件,並將新物件複製給指標。stringbad ditto (motto) //使用複製建構函式構造ditto
stringbad metto = motto
stringbad also = stringbad (motto)
stringbad * pstringbad = new stringbad (motto)
當函式按值傳遞物件或者函式返回物件時,都將會使用複製建構函式,每當程式生成了副本,編譯器都將會使用複製建構函式
注意: 由於使用按值傳遞的時候會呼叫複製建構函式,那麼會浪費一定的時間和空間,所以應該經常使用引用傳遞引數,這樣的話,可以節省呼叫建構函式的時間以及儲存空間。預設的複製建構函式的功能預設的複製建構函式逐個複製非靜態成員(成員複製也成為淺複製),複製的是成員的值。
淺複製建構函式帶來的缺陷淺複製建構函式會讓新的物件和以前的物件使用同乙個位址,那麼當呼叫析構函式的時候,析構了一次,但是會讓兩個物件都失去位址,然後gg思密達stringbad sailor = sports;
//與下面的函式等價
stringbad sailor;
sailor.str = sports.str
;sailor.len = sports.len
;
解決辦法
定義乙個顯示複製建構函式以解決問題
所謂的顯示複製建構函式,就是加了位址這一項。
stringbad::stringbad (const stringbad & st)
警告:如果類中包含了使用new初始化的指標成員,應當定義乙個複製建構函式,以複製指向的資料,而不是指標,這類被稱為深度複製。複製的另一種形式是淺複製,只是複製指標值,淺複製僅僅淺淺的複製指標資訊,而不會深入挖掘複製指標引用的結構運算子原型:
class_name & class_name::operator=(const class_name &);
賦值運算子的功能以及何時使用它將已有的物件賦給另乙個物件時,將使用過載的賦值運算子:
這個和上面的複製建構函式是有區別的複製建構函式:stringbad headline1 ("celery stalks at midnight");
stringbad knot;
knot = headline1; // 使用複製建構函式建立乙個臨時物件然後通過賦值將臨時物件複製到新的物件中。
/* 這樣就是說初始化總是會呼叫複製建構函式建立乙個臨時的物件。
然後通過賦值將臨時物件的值複製到新物件中。
*/
// 物件的宣告
stringbad metoo=knot
預設賦值運算子帶來的問題使用預設的賦值運算子所產生的問題的原因和複製運算子產生的問題原因是一樣的,都是同一塊位址,析構就沒有了。這裡的metto是乙個新建立的物件,被初始化knot的值,因此使用複製建構函式
這裡的knot是乙個先使用預設建構函式建立的物件,然後使用knot對其進行賦值操作
解決辦法—-建立乙個深複製函式
實現與複製函式一樣,但是也有一些小區別
由於目標物件可能引用了以前分配的資料,所以在使用之前使用delete進行釋放
函式應當避免將物件賦值給自身,否則,給新物件重新賦值前,釋放記憶體操作可能刪除的物件
函式返回乙個指向呼叫物件的引用。
參考 《c++ primer plus》stringbad & stringbad::operator=(const stringbad & st)
預設建構函式 建構函式 複製建構函式和賦值操作符
這幾個概念比較容易混淆,總結一下。預設建構函式是沒有引數 和類同名的建構函式。當乙個類沒有任何建構函式時,編譯器將會合成乙個預設建構函式。那麼編譯器合成的預設建構函式是做什麼用的呢?是初始化類的成員變數嗎?事實上不是。編譯器合成的預設建構函式只是滿足編譯器的需要,而不是按照程式設計師想的去做。更詳細...
複製建構函式與賦值函式
建構函式 析構函式 賦值函式是每個類最基本的的函式。每個類只有乙個析構函式和乙個賦值函式。但是有很多建構函式 乙個為複製建構函式,其他為普通建構函式。對於乙個類a,如果不編寫上述四個函式,c 編譯器將自動為a產生四個預設的函式,即 既然能自動生成函式,為什麼還需要自定義?原因之一是 預設的複製建構函...
複製建構函式跟賦值建構函式的區別
1.何時呼叫複製建構函式 複製建構函式用於將乙個物件複製到新建立的物件中。也就是說,它用於初始化過程中,而不是常規的賦值過程中。類的複製建構函式原型通常如下 class name const class name 它接受乙個指向類物件的常量引用作為引數。例如,string類的複製建構函式的原型如下 ...