c 筆記 類型別拷貝控制

2021-09-11 20:25:46 字數 2964 閱讀 5407

乙個類通過定義五種特殊的成員函式來控制物件的拷貝,移動,賦值和銷毀操作,分別是拷貝建構函式、拷貝賦值建構函式、移動建構函式、移動賦值運算子和析構函式。

拷貝和移動建構函式定義了當同型別的另乙個物件初始化本物件時,做什麼操作

拷貝和移動賦值運算子定義了乙個物件賦值給同型別的另乙個物件時,做什麼操作

析構函式定義了物件銷毀時,做什麼操作

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

class foo

;要求:

拷貝建構函式的第乙個引數必須是乙個引用型別。

雖然我們可以定義乙個接受非const引用的拷貝建構函式,但引數幾乎總是乙個const的引用。

如果我們沒有為乙個類定義拷貝建構函式,編譯器會為我們定義乙個。

過載運算子,本質上是函式,其名字由operator關鍵字,後接表示要定義的運算子的符號組成。類似任何其他函式,運算子函式也有乙個返回型別和引數列表

class foo

賦值運算子通常應該返回乙個指向其左側運算物件的引用。

foo& foo::operator=(const foo &ths)

析構函式,與建構函式相反的操作。建構函式初始化物件的非static資料成員,還可能做一些其他工作;析構函式釋放物件使用的資源,並銷毀物件的非static資料成員。析構函式也是類的乙個成員函式,由波浪號接類名構成,沒有返回值,也不接收引數。

隱式銷毀乙個內建指標型別的成員不會delete它所指的物件,應該手動釋放(塊作用域中的指標指向的物件)

//vec是區域性變數,p2是智慧型指標,因此離開作用域後會自己釋放掉。

當乙個類未定義自己的析構函式時,編譯器會為它定義乙個合成析構函式。

class foo

;class sales_data

//sales_data的合成析構函式

};

當乙個類需要析構函式時,我們幾乎可以肯定它也需要乙個拷貝建構函式和乙個拷貝賦值運算子。

class hasptr

private:

std::string *ps;

int i;

}這個類在建構函式中動態分配記憶體。合成析構函式不會delete乙個指標資料成員。

因此,此類需要定義乙個析構函式來釋放建構函式分配的記憶體。

class hasptr

~hasptr() //但是單單如此會產生錯誤

private:

std::string *ps;

int i;

}如果乙個類需要自定義析構函式,幾乎可以肯定需要自定義拷貝賦值運算和拷貝建構函式

需要拷貝操作的類也需要賦值操作,反之亦然

我們只能對具有合成版本的成員函式使用=default(即,預設建構函式或拷貝控制成員)

class sales_data

sales_data& sales_data::operator=(const sales_data&) = default;

新標準下,我們可以通過定義未刪除的函式來阻止拷貝。刪除的函式,即我們雖然宣告了他們,但是不能以任何方式使用他們。在函式的引數列表後加=delete來定義

struct nocopy

與=default不同的時,定義=delete宣告必須出現在函式第一次宣告時,而不能再在外部進行宣告。

#注意#

我們不能刪除析構函式,否則就無法銷毀此型別的物件。

explicit防止隱式轉換,explicit關鍵字只能用於類內部的建構函式宣告上,而不能用在類外部的函式定義上。

class things

int compareto(const things & other);

std::string m_name;

int height;

int weight;

};在使用該類時,這裡things的建構函式可以只用乙個實參完成初始化。所以可以進行乙個隱式轉換,像下面這樣:

things a;

................//在這裡被初始化並使用。

std::string nm ="book_1";

//由於可以隱式轉換,所以可以下面這樣使用

int result = a.compareto(nm);

#注意#

這段程式使用乙個string型別物件作為實參傳給things的compareto函式。

這個函式本來是需要乙個tings物件作為實參。現在編譯器使用string nm來構造並初始化乙個things物件,

新生成的臨時的things物件被傳遞給compareto函式,並在離開這段函式後被析構。

對於宣告為explicit的建構函式

class things

int compareto(const things & other);

std::string m_name;

int height;

int weight;

};在使用時不能再傳入string來隱式構造,必須顯示構造

std::string nm = "book_2";

int result = a.compareto(things(nm)); //必須顯示構造

這種行為的正確與否取決於業務需要。假如你只是想測試一下a的重量與10的大小之比,這麼做也許是方便的。但是假如在compareto函式中還涉及到了要除以初始化為0的height屬性,那麼這麼做可能就是錯誤的。需要在構造tings之後更改height屬性不為0。

google的c++規範中提到explicit的優點是可以避免不合時宜的型別變換,缺點無。所以google約定所有單引數的建構函式都必須是顯示的,只有極少數情況下拷貝建構函式可以不宣告稱explicit。

c 類的拷貝控制

當定義乙個類時,我們顯式地或隱式地指定在此型別的物件拷貝 移動 賦值和銷毀時做什麼。乙個類通過定義五種特殊的成員函式來控制這些操作。包括 拷貝建構函式 拷貝賦值運算子 移動建構函式 移動賦值運算子和析構函式。拷貝和移動建構函式定義了當用同型別的另乙個物件初始化本物件時做什麼。拷貝和移動賦值運算子定義...

C 拷貝控制 學習筆記

sales data sales data const sales data orig bookno orig.bookno units sold orig.units sold revenue orig.revenue string dots 10 直接初始化 string s dots 直接初始...

3 11 C 類的拷貝控制

但我們定義乙個類時,我們隱式或者顯式的指定此型別物件的拷貝 移動 賦值和銷毀時做什麼。具體就是通過五種特殊的建構函式,包括 拷貝建構函式 拷貝賦值運算子 移動建構函式 移動賦值運算子,析構函式。關於直接初始化和拷貝初始化 當使用直接初始化,我們是實際上是要求編譯器使用普通的函式匹配來選擇與我們提供的...