C++類和對象之默認成員函數(shù)的使用解讀
一、默認成員函數(shù)有哪些
C++ 類的默認成員函數(shù)主要有六個,分別是默認構(gòu)造函數(shù)、析構(gòu)函數(shù)、拷貝構(gòu)造函數(shù)、拷貝賦值運算符和移動構(gòu)造函數(shù)、移動賦值運算符(C++11 引入)。
它們各自承擔(dān)著不同的職責(zé),在對象的生命周期中發(fā)揮著關(guān)鍵作用。
二、各默認成員函數(shù)詳解
默認構(gòu)造函數(shù)
默認構(gòu)造函數(shù)是用于創(chuàng)建對象時初始化對象的特殊成員函數(shù)。它不需要任何參數(shù),如果我們沒有在類中顯式定義構(gòu)造函數(shù),編譯器會自動生成一個默認構(gòu)造函數(shù)。
構(gòu)造函數(shù)的存在完美的代替了Init函數(shù)的作用,并且由于他是自動調(diào)用,也方便使用了許多。
例如:
class MyClass {
// 編譯器會生成默認構(gòu)造函數(shù)
int data;
};在上述代碼中,MyClass類沒有顯式定義構(gòu)造函數(shù),編譯器會生成一個默認構(gòu)造函數(shù)。當使用MyClass obj;這樣的語句創(chuàng)建對象obj時,默認構(gòu)造函數(shù)就會被調(diào)用。
不過需要注意的是,編譯器生成的默認構(gòu)造函數(shù)只是對對象的成員進行默認初始化,對于內(nèi)置類型,其值是未定義的;對于類類型成員,則會調(diào)用該成員類的默認構(gòu)造函數(shù)進行初始化。
在類成員為自定義成員時,由于編譯器所構(gòu)造的函數(shù)不能夠完美滿足使用者的需求,所以大多數(shù)情況下要求用于自行去實現(xiàn)一個構(gòu)造函數(shù)。
構(gòu)造函數(shù)的特點:
- 函數(shù)名與類名相同。
- ?返回值,也不需要void。
- 對象實例化時系統(tǒng)會?動調(diào)?對應(yīng)的構(gòu)造函數(shù)。
- 構(gòu)造函數(shù)可以重載。
- 如果類中沒有顯式定義構(gòu)造函數(shù),則C++編譯器會?動?成?個?參的默認構(gòu)造函數(shù),?旦??顯式定義編譯器將不再?成。
- ?參構(gòu)造函數(shù)、全缺省構(gòu)造函數(shù)、我們不寫構(gòu)造時編譯器默認?成的構(gòu)造函數(shù),都叫做默認構(gòu)造函數(shù)。但是這三個函數(shù)有且只有?個存在,不能同時存在。?參構(gòu)造函數(shù)和全缺省構(gòu)造函數(shù)雖然構(gòu)成函數(shù)重載,但是調(diào)?時會存在歧義。要注意很多同學(xué)會認為默認構(gòu)造函數(shù)是編譯器默認?成那個叫默認構(gòu)造,實際上?參構(gòu)造函數(shù)、全缺省構(gòu)造函數(shù)也是默認構(gòu)造,總結(jié)?下就是不傳實參就可以調(diào)?的構(gòu)造就叫默認構(gòu)造。
- 我們不寫,編譯器默認?成的構(gòu)造,對內(nèi)置類型成員變量的初始化沒有要求,也就是說是是否初始化是不確定的,看編譯器。對于?定義類型成員變量,要求調(diào)?這個成員變量的默認構(gòu)造函數(shù)初始化。如果這個成員變量,沒有默認構(gòu)造函數(shù),那么就會報錯,我們要初始化這個成員變量,需要?初始化列表才能解決。
析構(gòu)函數(shù)
析構(gòu)函數(shù)與構(gòu)造函數(shù)相對,用于在對象生命周期結(jié)束時進行清理工作,釋放對象所占用的資源。析構(gòu)函數(shù)沒有返回值,也不需要參數(shù),并且名稱與類名相同,只是前面加上一個波浪號~。和默認構(gòu)造函數(shù)類似,如果我們沒有顯式定義析構(gòu)函數(shù),編譯器會生成一個默認析構(gòu)函數(shù)。
析構(gòu)函數(shù)主要代替的是destroy函數(shù)的作用,在類結(jié)束時自動調(diào)用銷毀。析構(gòu)函數(shù)主要處理的是經(jīng)過動態(tài)內(nèi)存申請的類。
class MyClass {
// 編譯器會生成默認析構(gòu)函數(shù)
int* data;
};對于大多數(shù)簡單類,默認析構(gòu)函數(shù)就足夠了,它會自動調(diào)用成員對象的析構(gòu)函數(shù),釋放對象成員占用的資源。但如果類中涉及到動態(tài)內(nèi)存分配,就需要顯式定義析構(gòu)函數(shù)來釋放這些動態(tài)分配的資源,否則會導(dǎo)致內(nèi)存泄漏。例如:
class MyClass {
public:
MyClass() {
data = new int;
}
~MyClass() {
delete data; // 顯式釋放動態(tài)分配的內(nèi)存
}
private:
int* data;
};析構(gòu)函數(shù)的特點:
- 析構(gòu)函數(shù)名是在類名前加上字符~。
- ?參數(shù)?返回值,則無void。
- ?個類只能有?個析構(gòu)函數(shù)。若未顯式定義,系統(tǒng)會?動?成默認的析構(gòu)函數(shù)。
- 對象?命周期結(jié)束時,系統(tǒng)會?動調(diào)?析構(gòu)函數(shù)。
- 跟構(gòu)造函數(shù)類似,我們不寫編譯器?動?成的析構(gòu)函數(shù)對內(nèi)置類型成員不做處理,?定類型成員會調(diào)?他的析構(gòu)函數(shù)。
- 還需要注意的是我們顯?寫析構(gòu)函數(shù),對于?定義類型成員也會調(diào)?他的析構(gòu),也就是說?定義類型成員?論什么情況都會?動調(diào)?析構(gòu)函數(shù)。
- 如果類中沒有申請資源時,析構(gòu)函數(shù)可以不寫,直接使?編譯器?成的默認析構(gòu)函數(shù);如果默認?成的析構(gòu)就可以?,也就不需要顯?寫析構(gòu);但是有資源申請時,?定要??寫析構(gòu),否則會造成資源泄漏。
拷貝構(gòu)造函數(shù)
拷貝構(gòu)造函數(shù)用于用一個已存在的對象創(chuàng)建一個新的對象,本質(zhì)上是進行對象的復(fù)制操作。它的參數(shù)是本類對象的常量引用,例如:
class MyClass {
public:
MyClass(int value) : data(value) {}
MyClass(const MyClass& other) : data(other.data) {} // 自定義拷貝構(gòu)造函數(shù)
private:
int data;
};如果我們沒有顯式定義拷貝構(gòu)造函數(shù),編譯器會生成一個默認的拷貝構(gòu)造函數(shù)。默認拷貝構(gòu)造函數(shù)會對對象的每個成員進行逐成員拷貝,對于基本數(shù)據(jù)類型,這種拷貝方式?jīng)]有問題;但對于指針類型成員,默認拷貝構(gòu)造函數(shù)只是簡單地復(fù)制指針的值,這可能會導(dǎo)致兩個對象的指針指向同一塊內(nèi)存,從而引發(fā)內(nèi)存管理問題。
拷貝賦值運算符
如果?個構(gòu)造函數(shù)的第?個參數(shù)是??類類型的引?,且任何額外的參數(shù)都有默認值,則此構(gòu)造函數(shù)也叫做拷?構(gòu)造函數(shù),也就是說拷?構(gòu)造是?個特殊的構(gòu)造函數(shù)。
拷貝賦值運算符用于將一個已存在的對象賦值給另一個同類型的對象,它的函數(shù)形式為類名& operator=(const 類名& other) 。同樣,如果沒有顯式定義,編譯器會生成默認的拷貝賦值運算符。
class MyClass {
public:
MyClass& operator=(const MyClass& other) {
if (this!= &other) {
data = other.data;
}
return *this;
}
private:
int data;
};默認的拷貝賦值運算符也會進行逐成員賦值,和默認拷貝構(gòu)造函數(shù)一樣,在處理指針類型成員時可能會出現(xiàn)問題。在實際編程中,當類涉及到資源管理時,我們需要自定義拷貝賦值運算符,確保資源的正確處理。
拷?構(gòu)造的特點:
- 拷?構(gòu)造函數(shù)是構(gòu)造函數(shù)的?個重載。
- 拷?構(gòu)造函數(shù)的第?個參數(shù)必須是類類型對象的引?,使?傳值?式編譯器直接報錯,因為語法邏輯上會引發(fā)?窮遞歸調(diào)????構(gòu)造函數(shù)也可以多個參數(shù),但是第?個參數(shù)必須是類類型對象的引?,后?的參數(shù)必須有缺省值。因為形參會創(chuàng)建一個臨時變量,這個臨時變量又會進行拷貝
- C++規(guī)定?定義類型對象進?拷??為必須調(diào)?拷?構(gòu)造,所以這??定義類型傳值傳參和傳值返回都會調(diào)?拷?構(gòu)造完成。
- 若未顯式定義拷?構(gòu)造,編譯器會?成?動?成拷?構(gòu)造函數(shù)。?動?成的拷?構(gòu)造對內(nèi)置類型成員變量會完成值拷?/淺拷?(?個字節(jié)?個字節(jié)的拷?),對?定義類型成員變量會調(diào)?他的拷?構(gòu)造。
- 傳值返回會產(chǎn)??個臨時對象調(diào)?拷?構(gòu)造,傳值引?返回,返回的是返回對象的別名(引?),沒有產(chǎn)?拷?。但是如果返回對象是?個當前函數(shù)局部域的局部對象,函數(shù)結(jié)束就銷毀了,那么使?引?返回是有問題的,這時的引?相當于?個野引?,類似?個野指針?樣。傳引?返回可以減少拷?,但是?定要確保返回對象,在當前函數(shù)結(jié)束后還在,才能?引?返回。
- 若是未進行動態(tài)內(nèi)存申請的數(shù)據(jù),則淺拷貝也能可以;但若進行了動態(tài)內(nèi)存分配,則需要自己實現(xiàn)一個拷貝構(gòu)造,來實現(xiàn)深拷貝。這是因為動態(tài)內(nèi)存分配的空間,淺拷貝時會指向同一塊空間,會析構(gòu)兩次導(dǎo)致程序崩潰。
三、默認成員函數(shù)的注意事項
注意事項:
- 在使用默認成員函數(shù)時,要特別注意類中成員的類型。
- 如果類包含指針類型成員或其他需要特殊資源管理的成員,一定要謹慎使用默認的拷貝構(gòu)造函數(shù)、拷貝賦值運算符等,避免出現(xiàn)內(nèi)存泄漏或懸空指針等問題。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
淺析string類字符串和C風(fēng)格字符串之間的區(qū)別
string類是標準庫的類,并不是內(nèi)置類型,標準庫就像是我們自己定義的類差不多的,string類型對象沒有標配'\0'結(jié)尾的2013-09-09
C++ Boost Coroutine使用協(xié)程詳解
通過Boost.Coroutine,可以在C++中使用協(xié)程。協(xié)程是其他編程語言的一個特性,通常使用關(guān)鍵字yield來表示協(xié)程。在這些編程語言中,yield可以像return一樣使用2022-11-11
C++數(shù)據(jù)結(jié)構(gòu)之哈希表的實現(xiàn)
哈希表,即散列表,可以快速地存儲和查詢記錄。這篇文章主要為大家詳細介紹了C++數(shù)據(jù)結(jié)構(gòu)中哈希表的實現(xiàn),感興趣的小伙伴可以了解一下2023-03-03

