內建型別和類型別複製控制的方方面面

2021-07-22 08:23:16 字數 2683 閱讀 4796

複製控制指的是通過複製的手段來控制資料的成員物件,其實在我們開發c++程式的時候,很經常用到複製控制,在我們沒有意識的情況下,系統使用的是預設的複製控制。由編譯器生成的複製控制相關函式是非常簡練的,因此,有時候使用系統為我們生成的複製控制函式是不能滿足我們的需求的,所以我們有必要了解複製控制的方方面面,用於更好的控制資料物件的生成,銷毀,賦值。賦值控制主要有三個方面:

①、複製建構函式:複製建構函式指的是只帶有乙個本型別的const引用物件的建構函式,當定義乙個同型別的物件的時候,將顯示呼叫複製建構函式。當我們呼叫函式的時候,傳遞的實參也是通過複製建構函式傳遞的,但是它是隱式的。這就能理解為什麼不支援複製操作的物件,比如流物件是不可以使用複製傳遞的方式傳遞引數了。當函式返回結果的時候,同樣也是使用複製建構函式進行的。

②、賦值操作:賦值時指將右運算元賦值給左運算元,預設情況下,系統會給我們預設定義,即使用複製建構函式給物件賦值。如果我們需要控制這個賦值過程,就需要過載賦值操作符了。

③、析構函式:即當乙個物件使用完畢之後,需要執行的操作。預設情況下,編譯器會自動執行所有非static物件的資源。如果我們 需要詳細控制物件的釋放,就需要重寫建構函式。

複製建構函式指的是只含有乙個本類型別物件的const引用形參的建構函式。它的主要作用是:

①、將另乙個同型別的物件顯示或者隱式的複製給另外乙個同型別的物件。

②、複製乙個物件,將它作為乙個實參傳遞給函式。

③、返回乙個物件,將它作為返回值返回。

直接初始化使用()初始化,複製初始化使用=。比如:

string s("sss");

string s1=s;

上述方式s是直接初始化的,s1的過程則是,先呼叫預設建構函式建立s1,然後將s通過複製建構函式建立乙個副本,複製給s1。

和預設建構函式不一樣,即使我們定義了其它建構函式,系統也會為我們合成乙個複製建構函式,合成的複製建構函式的行為是,將物件的資料成員的副本逐個傳遞給正在建立的物件的資料成員。除了static成員變數之外,其它的變數如果是內建型別,則賦值副本,如果是類型別,則使用類型別的複製建構函式進行複製。

除了接受系統合成的複製建構函式之外,我們也可以自己寫複製建構函式。如下:

class person

什麼情況下需要自己寫複製建構函式呢?因為系統合成的複製建構函式是逐一進行賦值的,除此之外不包含任何操作,因此,如果類含有指標型別的資料成員,或者含有需要分配資源的資料成員,就需要重寫複製建構函式進行特殊處理。

前面我們知道即使在我們沒有顯示重寫複製建構函式的情況下,系統也會合成乙個預設的建構函式。但有些時候,複製的成本過大,我們並不希望類的物件可以被複製,那麼要怎麼禁止呢?

我們可以宣告乙個複製建構函式,但是不要放在public區間,而是放在private之間,這樣編譯器將會拒絕任何該類的複製請求。如果我們需要為某個類開放複製功能,可以使用友元修飾符進行宣告。

和複製建構函式一樣,編譯器會我們合成乙個賦值操作,它的行為也是逐一進行賦值。如果我們需要修改這一行為,就需要自己寫賦值操作符了。賦值操作符是由operator=作為函式名,並且具有返回值和引數的。引數的數目和操作符的運算元相關。比如:

class person

可以發現賦值操作符做的工作和複製建構函式特別相似,因此,如果乙個類需要重寫複製建構函式那麼一般而言,他也需要重寫賦值建構函式。

析構函式的作用是用於釋放類物件持有的資源,比如類裡面持有的檔案資源等等。看如下**:

person *p=new person;

person person(*p);

delete(p);

假設上述**包含在乙個**快裡面,當超出作用域的時候,系統會自動自行persond的析構函式,而p的析構函式則不會執行。析構函式自動執行有兩個原則:

①、類的物件超出作用域的時候會呼叫析構函式

②、指標和類的引用超出作用域不會呼叫析構函式

即動態分配的的物件,我們必須顯式釋放它,比如上面如果不呼叫delete的話,就會造成記憶體洩漏,因為p永遠佔據著記憶體空間。對於容器型別和內建陣列的時候,也需要delete釋放記憶體,但是這些容器的釋放順序是從結尾到開頭的,即先釋放最後乙個元素,再到頭乙個元素。

person *p=new person[10];

vectorvect(p,p+10);

delete p;

這樣就可以刪除乙個陣列物件。

除了系統合成的析構函式外,我們也可以自己寫析構函式:

class person

//.......

}

和複製建構函式不一樣的地方在於,無論你是否有寫析構函式,系統都會執行預設合成的建構函式。比如person物件的釋放,先執行你寫的建構函式然後呼叫合成的建構函式。

什麼情況下應該重寫析構函式呢?當需要重寫預設建構函式和賦值操作符的時候,肯定就需要重寫預設建構函式,因為您需要處理資源的釋放。

最後提一點,類中包含指標成員物件的時候,切記要處理好。因為複製建構函式複製的是指標的值,即指向乙個物件的位址,這樣兩個指標會一起指向同乙個物件,很容易在乙個指標修改了物件的情況下,另乙個指標卻不知道。更嚴重的是,乙個指標將其釋放了,造成懸垂指標,另乙個指標卻不知道,仍在使用,會導致崩潰。

---------文章寫自:hyharden---------

C 複製值型別的變數和類

c 大多數基元型別包括int float double 和char等,注意這裡不包括string,這些都是值型別。將變數宣告為值型別,編譯器會生成 來分配足以容納這個值得記憶體塊。編譯器分配記憶體的時候並不是分配乙個能夠容納整個類的記憶體塊,它唯一做的事情就是分配乙個這個類的位址。c 的string...

複製(基本型別和引用型別)

一 基本型別複製 可以理解為把原模板a複製在另外乙個資料夾存為b中,改變b的內容不影響a的內容。舉例如下 var num1 12 var num2 num1 num2 13 console.log num1 輸出為12,不受num2的影響二 引用型別複製 可以理解為兩個都指向同乙個位址,乙個變數改變...

變數和基本內建型別

2.1基本內建型別 2.11.算數型別 分類 整型 integral type 與浮點型 c 算數型別 型別含義 最小尺寸 bool 布林型別 未定義char 字元8位 wchar t 寬字元16位 char16 t unicode字元 16位char32 t unicode字元 32位short ...