拷貝構造函數
注意點
1.類聲明隻描述如何配置設定記憶體,并不會配置設定記憶體。是以,不要在類聲明中初始化靜态成員變量。 特殊情況:靜态成員是const或者是枚舉型時,則應在類聲明中初始化。
2.會用到複制構造函數的聲明:
point a(b);
point a = b;
point a = point b;
point *a = new point(b)
中間兩個聲明是等價的。并且有兩種可能性,一種直接使用拷貝構造函數建立對象,一種使用拷貝構造函數建立一個臨時變量,再調用重載的指派運算符。
3.按值傳遞和傳回對象也将調用拷貝構造函數。
4.由于第三點原因,我們在寫函數參數時,應該使用引用傳遞對象,可以節省使用拷貝構造函數的時間和建立新對象的空間。
5.在類對象建立時,要避免淺複制(即使用了預設拷貝構造函數),兩個對象指向同一段空間,遇到析構函數時,将會發生同一段空間被釋放兩次的情況,将會引發報錯。
6.當我們看到類中的資料成員有指針變量或者靜态資料成員時,需要主動提供一個顯式拷貝構造函數
常見格式(深複制)
StringBad::StringBad(const StringBad &st)
{
num_string++; // 修改靜态成員變量,符合我們第6個注意點
len = st.len; // 長度
str = new char[len + 1]; // 配置設定了一段空間,加1的目的是預留給\0(字元串結束符)空間
strcpy(str, st.str); // 把字元串複制到配置設定的空間中
}
指派運算符重載
注意點
1.将一個已有對象指派給一個對象時,将會使用重載的指派運算符,在除初始化時,大部分兩個對象都有值了。
2.指派運算符不會産生新對象,是以不會對靜态成員變量産生影響。有人可能會産生疑惑,在初始化時,我們也要用到重載的指派運算符,那麼勢必需要修改靜态成員變量。其實,初始化,有兩種情況,之前已經說明了,細心的小夥伴已經發現了共同點,沒錯,初始化一定會使用拷貝構造函數,此時已經修改了靜态成員變量,不用再擔心了。
3.在重載指派運算符時,要避免将對象指派給自身。
常見格式
StringBad& StringBad::operator(const StringBad &st)
{
if(this == &st) // 首先檢查自我複制
{
return *this
}
delete[] str // 釋放可能有的舊的内容,防止之後産生記憶體洩漏
len = st.len // 長度
str = new char[len + 1] // 配置設定一段新空間
strcpy(str, st.str) // 把字元串複制到配置設定的空間中,此時若剛剛不delete空間,則會産生記憶體洩漏!
}