建構函式,拷貝構造和賦值運算子‘=‘的區別
例子
class CExample
{
private:
char *pBuffer; //類的物件中包含指標,指向動態分配的記憶體資源
int nSize;
public:
CExample() {pBuffer=NULL;nSize=0;}
~CExample() {delete pBuffer;}
void Init(int n) { pBuffer=new char[n]; nSize=n;}
};
int main( )
{
CExample theObjone; //物件建立,呼叫建構函式
theObjone.Init(40);
CExample theObjtwo=theObjone; //物件複製(因初始化),呼叫拷貝建構函式
(有指標成員,使用預設拷貝構造有缺點(僅複製指標),故要用自定義的)
CExample theObjthree;
theObjthree.Init(60);
theObjthree=theObjone; //物件賦值操作(因非初始化),呼叫賦值運算子
(有指標成員,使用默賦值符“=”有缺點(舊指標被丟棄),故要過載運算子)
}
注意:"="號的兩種不同使用,初始化和賦值
第三行也用到了"="號,該"="在物件宣告語句中,表示初始化。更多時候,這種初始化也可用括號()表示。而最後一行的"="號是賦值符,使用預設賦值符"=",是把被賦值物件的原內容被清除,並用右邊物件的內容填充。
建構函式 主要用來在建立物件時, 即為物件成員變數賦初始值
拷貝建構函式 形式為X(X&),用來完成基於同一類的其他物件的構建及初始化
一個物件需要通過另外一個物件進行初始化,呼叫拷貝建構函式。
初始化和賦值的不同含義是建構函式呼叫的原因。事實上,拷貝建構函式是由普通建構函式和賦值操作符共同實現的
預設拷貝建構函式(淺拷貝)
CExample theObjtwo=theObjone;"用theObjone初始化theObjtwo。
呼叫預設拷貝構造含, 其完成方式是記憶體拷貝(淺拷貝),複製所有成員的值。
完成後,theObjtwo.pBuffer==theObjone.pBuffer。 即它們將指向同樣的地方,指標雖然複製了,但所指向的空間並沒有複製,而是由兩個物件共用了。
這樣不符合要求,物件之間不獨立了,併為空間的刪除帶來隱患(產生野指標)
自定義拷貝建構函式(深拷貝)
因此可以在建構函式中新增操作來解決指標成員的問題,即自定義的拷貝建構函式
//自定義拷貝建構函式
CExample::CExample(const CExample& RightSides)
{
nSize=RightSides.nSize; //複製常規成員
pBuffer=new char[nSize]; //複製指標指向的內容
memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof(char));
}
這樣,定義新物件,並用已有物件初始化新物件時,CExample(const CExample& RightSides)將被呼叫,而已有物件用別名RightSides傳給建構函式,以用來作複製。
原則上,應該為所有包含動態分配成員的類都提供自定義的拷貝建構函式。
注意:記憶體拷貝函式void *memcpy(void *dest, constvoid *src, size_t n)
預設賦值操作符"="
//賦值操作符過載
CExample & CExample::operator = (const CExample& RightSides)
{
nSize=RightSides.nSize; //複製常規成員
char *temp=new char[nSize];//複製指標指向的內容(預設=的缺點)
memcpy(temp,RightSides.pBuffer,nSize*sizeof(char));
delete []pBuffer; //刪除原指標指向內容(避免記憶體洩露)
pBuffer=NULL; //同時把原指標置為NULL(避免野指標)
pBuffer=temp; //建立新指向
return *this ;
}
"="的預設(預設)操作只是將成員變數的值相應複製,舊的值被自然丟棄
最後一行的"="表示賦值操作,將物件theObjone的內容複製到物件theObjthree,這其中涉及到物件theObjthree原有內容的丟棄,新內容的複製。
由於物件內包含指標,將造成不良後果:指標的值被丟棄了,但指標指向的內容並未釋放(導致記憶體洩露)。指標的值被複制了,但指標所指內容並未複製(導致新指標指的內容丟了)
即產生兩方面的問題:丟棄舊指標(導致記憶體洩露),僅複製新指標(導致內容丟了)
因此,包含動態分配成員的類除了提供拷貝建構函式外,還應該考慮過載"="賦值操作符號
過載"="賦值操作符
--------------------- 本文來自 日月行者 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/qq_16445683/article/details/46043505?utm_source=copy