在c++中,如果我們定義乙個類,沒有定義任何的建構函式,那麼編譯器會為我們提供兩個特殊的建構函式:無參建構函式和拷貝建構函式
無參建構函式:其實就是乙個沒有引數、函式體為空的建構函式
拷貝建構函式:函式引數為 const class_name&,拷貝建構函式只是簡單的進行成員變數的賦值
下邊來看下邊兩個類test1和test2
test1中我們沒有定義任何建構函式,實則編譯器會預設提供乙個無參建構函式和乙個拷貝建構函式,這時候test1類中其實是有乙個無參建構函式test1(){}和乙個拷貝建構函式test1(const test1& obj){}
class test1
;class test2
test2(const test2& obj){}
};
對於無參建構函式,比較簡單,下邊我們重點來看看拷貝建構函式,上邊說了,編譯器提供的預設拷貝建構函式,能簡單的進行物件成員的賦值,那麼我們以下邊的**來驗證驗證:
#include #include using namespace std;
class test1
void setj(int j)
int geti()
int getj()
};int main()
編譯輸出:
從**中我們看到,對於test1類,我們沒有定義任何建構函式,所以編譯器會為我們提供兩個預設的建構函式,乙個無參建構函式,乙個拷貝建構函式,在執行到test1 t2 = t1 這條語句時,會呼叫拷貝建構函式,將t1的內容複製乙份給t2,跟我們c語言中的乙個變數賦值給另乙個變數道理是一樣的,這裡由於我們沒有定義拷貝建構函式,所以呼叫的是編譯器提供的預設拷貝建構函式,進行成員m_i與m_j的值得賦值,從而使得t2中的成員變數與t1中的成員變數一致。
相信你對c++的拷貝建構函式已經有了乙個初步的認識,但是在c++中,拷貝建構函式還分為深拷貝和淺拷貝
深拷貝:物件的邏輯狀態相同
淺拷貝:物件的物理狀態相同(即只是對物件成員進行簡單的複製)
編譯器為我們提供的只是淺拷貝
在討論深拷貝前,我們先來看下邊的一段**:
#include #include using namespace std;
class test1
void seti(int i)
void setj(int j)
int geti()
int getj()
int* getp()
void freep()
};int main()
編譯執行一下:
可以看到,程式其實已經崩潰了,分析一下就知道是執行t1.freep()和t2.freep()這兩個函式奔潰的,細心的朋友會發現,t1.getp()跟t2.getp()返回的值是一樣的,也就是說t1和t2物件的成員指標變數m_p是一樣,t1和t2執行freep()函式時,導致同乙個位址釋放了兩次,所以程式會奔潰,上邊**執行預設的拷貝建構函式後,其實物件的指標成員變數就如下圖所示,指向的是同一片記憶體空間。
為了解決程式奔潰問題,我們首先來分析下上邊的**,前邊我們說過,我們如果沒有定義建構函式,那麼編譯器會預設提供乙個拷貝建構函式,而提供的拷貝建構函式只是淺拷貝,也就是只能簡單的進行物件成員的複製,所以在執行test1 t2 = t1時,只是簡單的把t1中的m_p變數的值賦值給 t2中m_p變數,並沒有分配額外的空間,這就導致了同乙個記憶體位址會釋放兩次的原因。
有了以上的分析,我們就可以重寫拷貝建構函式來解決這個問題,改寫的**如下,其中我們重新實現了拷貝建構函式:
#include #include using namespace std;
class test1
test1(const test1& obj) //重新實現拷貝建構函式
void seti(int i)
void setj(int j)
int geti()
int getj()
int* getp()
int getpvalue()
void freep()
};int main()
編譯執行一下:
可以看到,t1和t2中的m_p指標變數的值已經不想同了,此時兩個物件釋放的就不是同乙個記憶體空間了;同時它們的空間的值是相同的,都為100,這就是我們想要的,這就是我們所說的深拷貝。
c++中需要深拷貝的情況一般是有成員指代了系統資源,如動態使用記憶體空間、開啟外部檔案、使用網路埠等等,就需要深拷貝。
在c++中預設的潛規則是,如果自己要實現拷貝建構函式,必須要實現成深拷貝。
最後總結一下:
-c++編譯器會預設提供建構函式
-無參建構函式用於定義物件的預設初始化狀態
-拷貝建構函式在建立物件時拷貝物件的狀態
-物件的拷貝有淺拷貝(物理狀態相同)和深拷貝(邏輯狀態相同)
-自己定義的拷貝建構函式,必須要實現深拷貝
C 物件的構造
物件是依據某個類模板建立的客觀存在,既然是客觀存在那麼它在某一時刻的狀態應該是確定,所以我們在建立物件的時候需要固定其狀態,也就是初始化,這就是建構函式的作用,初始化物件。class test test int i 物件的構造一般有3 種方式 test t 2 test t 2 test t tes...
C 19 物件的構造(下)
兩個特殊的建構函式 無參建構函式 當類中沒有定義建構函式時,編譯器預設提供乙個無參建構函式,並且其函式體為空。拷貝建構函式 當類中沒有定義拷貝建構函式時,編譯器預設提供乙個建構函式,簡單的進行成員變數的值複製。面試題 class t 這裡面的其實裡面有隱藏的建構函式和拷貝建構函式 有乙個概念要理清 ...
C 物件的構造順序
在c 中物件的構造順序有三種 1 區域性構造物件順序 2 堆物件構造順序 3 全域性物件構造順序 1 區域性構造物件順序構造物件例子 當程式執行流到達物件的定義語句時進行構造 include class test test const test obj int main if i 4 else re...