一. 什麼是拷貝建構函式
對於乙個類x, 如果乙個建構函式的第乙個引數是下列之一:
a) x&
b) const x&
c) volatile x&
d) const volatile x&
且沒有其他引數或其他引數都有預設值,那麼這個函式是拷貝建構函式.
二. 拷貝建構函式的呼叫時機
在c++中,下面三種物件需要呼叫拷貝建構函式!
1. 物件以值傳遞的方式傳入函式引數
2. 物件以值傳遞的方式從函式返回
3. 物件需要通過另外乙個物件進行初始化
三. 淺拷貝和深拷貝
1. 淺拷貝
所謂淺拷貝,指的是在物件複製時,只對物件中的資料成員進行簡單的賦值
,預設拷貝建構函式執行的也是淺拷貝。大多情況下「淺拷貝」已經能很好地
工作了,但是一旦物件存在了動態成員,那麼淺拷貝就會出問題了,讓我們考慮如下一段**:
[c-sharp]view plain
copy
class
rect
~rect() // 析構函式,釋放動態分配的空間
} private
: int
width;
intheight;
int*p;
// 一指標成員
};
intmain()
在這段**執行結束之前,會出現乙個執行錯誤。原因就在於在進行物件複製時,對於動態分
配的內容沒有進行正確的操作。我們來分析一下:
在執行定義rect1物件後,由於在建構函式中有乙個動態分配的語句,因此執行後的記憶體情況大
致如下:
在使用rect1複製rect2時,由於執行的是淺拷貝,只是將成員的值進行賦值,這時 rect1.p
= rect2.p,也即這兩個指標指向了堆裡的同乙個空間,如下圖所示:
當然,這不是我們所期望的結果,在銷毀物件時,兩個物件的析構函式將對同乙個記憶體空間釋放兩
次,這就是錯誤出現的原因。我們需要的不是兩個p有相同的值,而是兩個p指向的空間有相同的值
,解決辦法就是使用「深拷貝」。
2. 深拷貝
在「深拷貝」的情況下,對於物件中動態成員,就不能僅僅簡單地賦值了,而應該重新動態分
配空間,如上面的例子就應該按照如下的方式進行處理:
[c-sharp]view plain
copy
class
rect
rect(const
rect& r)
~rect() // 析構函式,釋放動態分配的空間
} private
: int
width;
intheight;
int*p;
// 一指標成員
};
此時,在完成物件的複製後,記憶體的乙個大致情況如下:
此時rect1的p和rect2的p各自指向一段記憶體空間,但它們指向的空間具有相同的內容,這就是所謂
的「深拷貝」。
class
cexample
cexample(
const
cexample & ex)
//拷貝建構函式
cexample&
operator
= (const
cexample &ex)
//賦值函式(賦值運算子過載)
void
mytestfunc(cexample ex)
};拷貝建構函式的引數為什麼必須使用引用型別?
cexample
ccc = aaa;
構造ccc,實質上是ccc.cexample(aaa); 我們假如拷貝構造函式引數不是引用型別的話, 那麼將使得 ccc.cexample(aaa)變成aaa傳值給ccc.cexample(cexample ex),即cexample ex = aaa,因為 ex 沒有被初始化, 所以 cexample ex = aaa 繼續呼叫拷貝建構函式,接下來的是構造ex,也就是 ex.cexample(aaa),必然又會有aaa傳給cexample(cexample ex), 即 cexample ex = aaa;那麼又會觸發拷貝建構函式,就這下永遠的遞迴下去。
所以繞了那麼大的彎子,就是想說明拷貝建構函式的引數使用引用型別不是為了減少一次記憶體拷貝, 而是避免拷貝建構函式無限制的遞迴下去。
所以, 拷貝建構函式是必須要帶引用型別的引數的, 而且這也是編譯器強制性要求的
拷貝建構函式,預設拷貝建構函式
拷貝建構函式,預設拷貝建構函式 1.c 的預設拷貝建構函式,從深度拷貝和淺拷貝說起 c 類的預設拷貝建構函式的弊端 c 類的中有兩個特殊的建構函式,1 無參建構函式,2 拷貝建構函式。它們的特殊之處在於 1 當類中沒有定義任何建構函式時,編譯器會預設提供乙個無參建構函式且其函式體為空 2 當類中沒有...
建構函式 拷貝建構函式
建構函式可以分為三類 1 不帶引數的建構函式 在函式體中對資料成員賦初值,這種方式使該類的每乙個物件都得到同一組初值 2 帶引數的建構函式 如果使用者希望對不同的物件賦不同的初值,可以採用帶引數的建構函式。在呼叫不同物件的建構函式時從外面將不同的資料傳遞給建構函式,以實現初始化 3 複製建構函式 建...
建構函式 拷貝建構函式
person person 引用就是指標常量 所以person p person const p,引用所以一旦初始化指向某個位址,就不能在改變了。為什麼前面還要加const,因為拷貝建構函式的目的就是將乙個物件的所有屬性拷貝到另外乙個物件,這個物件的屬性不變,加上const 相當於 const pe...