拷貝建構函式 拷貝賦值運算子和析構函式

2021-08-21 17:07:03 字數 1359 閱讀 4499

當定義乙個類時,我們顯式或隱式的指定物件拷貝,移動,複製和銷毀時做什麼。通過5類特殊成員函式來控制這些操作:拷貝建構函式、拷貝複製運算子、移動建構函式、移動複製運算子和析構函式。如果乙個類沒有定義這些,編譯器會自動定義缺失的操作。但對於一些類來說,預設定義可能導致災難。

拷貝建構函式定義了當用同型別物件初始化另乙個物件時做什麼。

如果乙個建構函式的第乙個引數是自身型別的引用,且任何額外引數都有預設值,則此建構函式為拷貝建構函式。

class foo

雖然我們可以定義非const引用,但該引數幾乎總是乙個const引用。

為何引數是引用?:

如果不是引用,在呼叫拷貝建構函式時我們需要拷貝它的實參,但為了拷貝它的實參,我們又需要呼叫它的拷貝建構函式,呼叫永遠不會成功。

如果我們沒有定義拷貝建構函式,編譯器缺省會合成乙個。它會依次將給定物件的非靜態成員變數逐個拷貝到正在建立的物件中。

內建成員變數直接拷貝,類物件成員使用其拷貝函式,陣列則是逐個元素拷貝。

string dot(3,'.');  //直接初始化,dot="..."

string s(dot); //直接初始化

string s1=dot; //拷貝初始化 使用=,將=右值拷貝來初始化左值,沒使用=則為直接初始化

string s2="123" //拷貝初始化

string s3=string("123") //拷貝初始化

當使用關鍵字explicit,必須顯性使用建構函式。

對於某些型別,這一情況非常理想。但在大部分情況中,隱式轉換卻容易導致錯誤(不是語法錯誤,編譯器不會報錯)。隱式轉換總是在我們沒有察覺的情況下悄悄發生,除非有心所為,隱式轉換常常是我們所不希望發生的。通過將建構函式宣告為explicit(顯式)的方式可以抑制隱式轉換。也就是說,explicit建構函式必須顯式呼叫。

引用一下bjarne stroustrup的例子:

class string析構函式可以用來釋放物件使用的資源,並銷毀非static資料成員。預設的合成析構函式為空,執行空函式體後成員自動銷毀。函式本身並不直接銷毀成員。成員在析構函式體後隱含的析構階段被銷毀。整個物件銷毀過程中,析構函式體是作為成員銷毀步驟之外的另一部分進行的。

波浪號+類名,如:~foo();

析構函式不接受引數,不能被過載,乙個類只有唯一析構函式。

無論何時物件被銷毀就會自動呼叫其析構函式:

通常需要析構函式的類也需要拷貝建構函式。類成員存在動態記憶體分布時,使用合成的建構函式會使得多個物件指向相同的記憶體,使用預設的合成析構函式會delete多次,會導致錯誤發生。

拷貝建構函式和賦值運算子

把引數傳遞給函式有三種方法,一種是值傳遞,一種是傳位址,還有一種是傳引用。前者與後兩者不同的地方在於 當使用值傳遞的時候,會在函式裡面生成傳遞引數的乙個副本,這個副本的內容是按位從原始引數那裡複製過來的,兩者的內容是相同的。當原始引數是乙個類的物件時,它也會產生乙個物件的副本,不過在這裡要注意。一般...

拷貝建構函式和賦值運算子

來自 本文主要介紹了拷貝建構函式和賦值運算子的區別,以及在什麼時候呼叫拷貝建構函式 什麼情況下呼叫賦值運算子。最後,簡單的分析了下深拷貝和淺拷貝的問題。在預設情況下 使用者沒有定義,但是也沒有顯式的刪除 編譯器會自動的隱式生成乙個拷貝建構函式和賦值運算子。但使用者可以使用delete來指定不生成拷貝...

拷貝建構函式 拷貝賦值運算子的總結

一般編譯器會自定義預設的拷貝建構函式,但是當類中含有指標成員時,常常需要我們自己定義拷貝建構函式。基本原則 1 當我們需要自定義析構函式時,通常也需要自定義拷貝建構函式。2 需要拷貝建構函式時通常也需要自定義拷貝賦值運算子,反之亦然。有兩種拷貝方式,深拷貝和淺拷貝。當我們自定義的類中有指標型別的資料...