目錄:
寫在前面
1)C++的編譯器會默認給一個類提供4個函數
- 默認構造函數(無參、函數體爲空)
- 默認析構函數(無參、函數體爲空)
- 默認拷貝函數(淺拷貝,對屬性僅進行值拷貝)
- 賦值運算符operator=(對屬性進行值拷貝)
我們知道類中的默認拷貝構造函數和賦值運算符,都是對屬性進行值拷貝,但是它們之間有什麼區別嗎?在什麼情況下會調用它們?下面會詳細介紹.
2)本篇涉及內容:
- 拷貝構造函數和賦值運算符的區別
- 如何實現賦值運算符的深拷貝
拷貝構造函數和賦值運算符
從上面代碼我們可以知道:
- 默認的拷貝構造函數和賦值運算符重載都是對屬性進行簡單的值拷貝(淺拷貝),如果屬性中有涉及到堆內存的使用需要進行函數重寫
那麼在什麼情況下會調用拷貝構造函數和賦值運算符重載?
-
調用拷貝構造函數的情況:
-
通過一個已存在的對象來構造一個新的對象,此時會調用這個新對象的拷貝構造函數.
-
當一個對象作爲函數實參傳入時,此時會調用形參的拷貝構造函數.
-
當函數的返回值是一個對象時,此時接受這個函數返回值的對象會調用拷貝構造函數.
從上面的情況我們可以總結出:
當一個已經構造好了的對象去賦值給一個還未構造的對象,此時就會調用這個還未構造的對象的拷貝構造函數,產生的結果是會有新的對象產生.關於深淺拷貝和拷貝構造函數的詳細介紹請看:C++的堆與拷貝構造函數
-
-
調用賦值運算符重載的情況:
-
兩個對象已經存在,用對象p1去重新賦值給另一個對象p2即
p2 = p1
,此時會調用p2對象的運算符重載.從上述情況我們可以得出:
當一個已經構造好了的對象去重新賦值給另一個構造好了的對象,此時就會調用這個被賦值的對象的運算符重載,這個過程中沒有新對象產生.
-
實現賦值運算符重載的深拷貝
下面仔細來看一下實現賦值運算符重載的深拷貝代碼
Person& operator= (Person& p) {
//先判斷原來的對象是否存在堆區
if (this->m_Age != NULL) {
delete this->m_Age;
this->m_Age = NULL;
}
//深拷貝
this->m_Age = new int(*p.m_Age);
//返回對象本身
return *this;
}
我們可以看見,實現深拷貝的原理和實現拷貝構造函數深拷貝的原理相同,但是這裏需要注意的是:
- 進行深拷貝之前要先把原來已經存在的堆內存釋放掉
- 返回值是當前對象本身的引用