C++修煉之構(gòu)造函數(shù)與析構(gòu)函數(shù)
??默認(rèn)成員函數(shù)
上一章中我們談到,如果一個(gè)類中什么成員也沒有,那么這個(gè)類就叫作空類。其實(shí)這么說是不太嚴(yán)謹(jǐn)?shù)?,因?yàn)?code>一個(gè)類不可能什么都沒有。
當(dāng)我們定義好一個(gè)類,不做任何處理時(shí),編譯器會(huì)自動(dòng)生成以下6個(gè)默認(rèn)成員函數(shù):
默認(rèn)成員函數(shù):如果用戶沒有手動(dòng)實(shí)現(xiàn),則編譯器會(huì)自動(dòng)生成的成員函數(shù)
構(gòu)造函數(shù):主要完成初始化工作;析構(gòu)函數(shù):主要完成清理工作;拷貝構(gòu)造:使用一個(gè)同類的對(duì)象初始化創(chuàng)建一個(gè)對(duì)象;賦值重載:把一個(gè)對(duì)象賦值給另一個(gè)對(duì)象;取地址重載:普通對(duì)象取地址操作;取地址重載(const):const對(duì)象取地址操作;
本章我們將學(xué)習(xí)兩個(gè)默認(rèn)成員函數(shù)——構(gòu)造函數(shù)與析構(gòu)函數(shù)。
??構(gòu)造函數(shù)
??引例
在C語言階段,我們實(shí)現(xiàn)棧的數(shù)據(jù)結(jié)構(gòu)時(shí),有一件事很苦惱,就是每當(dāng)創(chuàng)建一個(gè)stack對(duì)象(之前叫作定義一個(gè)stack類型的變量)后,首先得調(diào)用它的專屬初始化函數(shù)StackInit來初始化對(duì)象。
typedef int dataOfStackType;
typedef struct stack
{
dataOfStackType* a;
int top;
int capacity;
}stack;
void StackInit(stack* ps);
//...
int main()
{
stack s;
StackInit(&s);
//...
return 0;
}
這不免讓人覺得有點(diǎn)麻煩。在C++中,構(gòu)造函數(shù)為我們很好的解決了這一問題。
??構(gòu)造函數(shù)的概念及特性
構(gòu)造函數(shù)是一個(gè)特殊的成員函數(shù)。構(gòu)造函數(shù)雖然叫作構(gòu)造,但是其主要作用并不是開辟空間創(chuàng)建對(duì)象,而是初始化對(duì)象。
構(gòu)造函數(shù)之所以特殊,是因?yàn)橄啾扔谄渌蓡T函數(shù),它具有如下特性:
- 函數(shù)名與類名相同;
- 無返回值;
- 對(duì)象實(shí)例化時(shí),編譯器
自動(dòng)調(diào)用對(duì)應(yīng)的構(gòu)造函數(shù); - 構(gòu)造函數(shù)可以重載;
??舉例??
class Date
{
public:
//無參的構(gòu)造函數(shù)
Date()
{};
//帶參的構(gòu)造函數(shù)
Date(int year,int month,int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
void TestDate()
{
Date d1;//調(diào)用無參構(gòu)造函數(shù)(自動(dòng)調(diào)用)
Date d2(2023, 3, 29);//調(diào)用帶參構(gòu)造函數(shù)(自動(dòng)調(diào)用)
}
??特別注意??
- 創(chuàng)建對(duì)象時(shí)編譯器會(huì)自動(dòng)調(diào)用構(gòu)造函數(shù),若是
調(diào)用無參構(gòu)造函數(shù),則無需在對(duì)象后面使用()。否則會(huì)產(chǎn)生歧義:編譯器無法確定你是在聲明函數(shù)還是在創(chuàng)建對(duì)象。
??錯(cuò)誤示例??
//錯(cuò)位示例 Date d3();
- 如果類中沒有顯式定義構(gòu)造函數(shù),則C++編譯器會(huì)自動(dòng)生成一個(gè)無參的默認(rèn)構(gòu)造函數(shù),一旦用戶顯式定義編譯器將不再生成。
class Date
{
public:
//若用戶沒有顯示定義,則編譯器自動(dòng)生成。
/*Date(int year,int month,int day)
{
_year = year;
_month = month;
_day = day;
}*/
private:
int _year;
int _month;
int _day;
};
- 默認(rèn)生成構(gòu)造函數(shù),對(duì)內(nèi)置類型成員不作處理;對(duì)自定義類型成員,會(huì)調(diào)用它的默認(rèn)構(gòu)造函數(shù);
- C++把類型分成
內(nèi)置類型(基本類型)和自定義類型。內(nèi)置類型就是語言提供的數(shù)據(jù)類型,如:int、char、double…,自定義類型就是我們使用class、struct、union等自己定義的類型。
??舉例??
??默認(rèn)構(gòu)造函數(shù)對(duì)內(nèi)置類型??
class Date
{
public:
//此處不對(duì)構(gòu)造函數(shù)做顯示定義,測(cè)試默認(rèn)構(gòu)造函數(shù)
/*Date()
{}*/
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
void TestDate1()
{
Date d1;
d1.print();
}

- 如圖所示,默認(rèn)構(gòu)造函數(shù)的確未對(duì)內(nèi)置類型做處理。
??默認(rèn)構(gòu)造函數(shù)對(duì)自定義類型??
class stack
{
public:
//此處對(duì)stack構(gòu)造函數(shù)做顯示定義
stack()
{
cout <<"stack()" << endl;
_a = nullptr;
_top = _capacity = 0;
}
private:
int* _a;
int _top;
int _capacity;
};
class queue
{
public:
//此處不對(duì)queue構(gòu)造函數(shù)做顯示定義,測(cè)試默認(rèn)構(gòu)造函數(shù)
/*queue()
{}*/
private:
//自定義類型成員
stack _s;
};
void TestQueue()
{
queue q;
}

- 如圖所示,在創(chuàng)建
queue對(duì)象時(shí),默認(rèn)構(gòu)造函數(shù)對(duì)自定義成員_s做了處理,調(diào)用了它的默認(rèn)構(gòu)造函數(shù)stack()。
這一波蜜汁操作讓很多C++使用者感到困惑與不滿,為什么要針對(duì)內(nèi)置類型和自定義類型做不同的處理呢?終于,在C++11中針對(duì)內(nèi)置類型成員不初始化的缺陷,又打了補(bǔ)丁,即:
- 內(nèi)置類型成員變量在類中聲明時(shí)可以給默認(rèn)值;
??舉例??
class Date
{
public:
//...
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
//使用默認(rèn)值
int _year = 0;
int _month = 0;
int _day = 0;
};
void TestDate2()
{
Date d2;
d2.print();
}

默認(rèn)值:若不對(duì)成員變量做處理,則使用默認(rèn)值。
- 無參的構(gòu)造函數(shù)和全缺省的構(gòu)造函數(shù)都稱為默認(rèn)構(gòu)造函數(shù),并且默認(rèn)構(gòu)造函數(shù)只能有一個(gè);
??舉例??
class Date
{
public:
//無參的默認(rèn)構(gòu)造函數(shù)
//Date()
//{
//}
//全缺省的默認(rèn)構(gòu)造函數(shù)
Date(int year = 0, int month = 0, int day = 0)
{
_year = year;
_month = month;
_day = day;
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year = 0;
int _month = 0;
int _day = 0;
};
??析構(gòu)函數(shù)
析構(gòu)函數(shù)與構(gòu)造函數(shù)的特性相似,但功能有恰好相反。構(gòu)造函數(shù)是用來初始化對(duì)象的,析構(gòu)函數(shù)是用來銷毀對(duì)象的。
- 需要注意的是,
析構(gòu)函數(shù)并不是對(duì)對(duì)象本身進(jìn)行銷毀(因?yàn)榫植繉?duì)象出了作用域會(huì)自行銷毀,由編譯器來完成),而是在對(duì)象銷毀時(shí)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),對(duì)對(duì)象內(nèi)部的資源做清理(例如stack _s中的int* a)。
同樣,有了析構(gòu)函數(shù),我們?cè)僖膊挥脫?dān)心創(chuàng)建對(duì)象(或定義變量)后由于忘記釋放內(nèi)存而造成內(nèi)存泄漏了。
??舉例??
class Stack
{
public:
Stack()
{
//...
}
void Push(int x)
{
//...
}
bool Empty()
{
// ...
}
int Top()
{
//...
}
void Destory()
{
//...
}
private:
// 成員變量
int* _a;
int _top;
int _capacity;
};
void TestStack()
{
Stack s;
st.Push(1);
st.Push(2);
//過去需要手動(dòng)釋放
st.Destroy();
}
??析構(gòu)函數(shù)的特性
- 析構(gòu)函數(shù)名是在類名前加上字符
~; - 無參數(shù);
- 無返回值;
- 一個(gè)類只能有一個(gè)析構(gòu)函數(shù)。若未顯式定義,系統(tǒng)會(huì)自動(dòng)生成默認(rèn)的析構(gòu)函數(shù);
- 析構(gòu)函數(shù)不能重載;
??舉例??
class Date
{
public:
Date()
{
cout << "Date()" << endl;
}
~Date()
{
cout << "~Date()" << endl;
}
private:
int _year = 0;
int _month = 0;
int _day = 0;
};
void TestDate3()
{
Date d3;
//d3生命周期結(jié)束時(shí)自動(dòng)調(diào)用構(gòu)造函數(shù)
}

為便于觀察,我們可以在析構(gòu)函數(shù)內(nèi)部寫點(diǎn)兒東西。
- 編譯器生成的默認(rèn)析構(gòu)函數(shù),對(duì)自定類型成員調(diào)用它的析構(gòu)函數(shù);
??舉例??
class stack
{
public:
//此處對(duì)stack構(gòu)造函數(shù)做顯示定義
stack()
{
cout <<"stack()" << endl;
_a = nullptr;
_top = _capacity = 0;
}
~stack()
{
cout << "~Stack()" << endl;
free(_a);
_a = nullptr;
_top = _capacity = 0;
}
private:
int* _a;
int _top;
int _capacity;
};
class queue
{
public:
//此處不對(duì)queue構(gòu)造函數(shù)做顯示定義,測(cè)試默認(rèn)構(gòu)造函數(shù)
/*queue()
{}*/
private:
//自定義類型成員
stack _s;
};
void TestQueue1()
{
queue q;
}

- 這里可能有小伙伴會(huì)好奇:
為什么析構(gòu)函數(shù)不像構(gòu)造函數(shù)那樣區(qū)分內(nèi)置類型與自定義類型呢?
答案是:因?yàn)閮?nèi)置類型壓根不需要我們擔(dān)心清理工作,在其生命周期結(jié)束時(shí)會(huì)自動(dòng)銷毀。而自定義類型需要擔(dān)心,因?yàn)樽远x類型里可能含有申請(qǐng)資源(例如:malloc申請(qǐng)內(nèi)存須手動(dòng)釋放)。
- 如果類中沒有申請(qǐng)資源時(shí),析構(gòu)函數(shù)可以不寫,直接使用編譯器生成的默認(rèn)析構(gòu)函數(shù),比如
Date類;有資源申請(qǐng)時(shí),一定要寫,否則會(huì)造成資源泄漏,比如stack類。
到此這篇關(guān)于C++修煉之構(gòu)造函數(shù)與析構(gòu)函數(shù)的文章就介紹到這了,更多相關(guān)C語言 構(gòu)造函數(shù)與析構(gòu)函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用Matlab實(shí)現(xiàn)圖像亮度分布統(tǒng)計(jì)圖
這篇文章主要介紹了如何利用Matlab實(shí)現(xiàn)圖像亮度分布統(tǒng)計(jì)圖的繪制,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Matlab有一定的幫助,感興趣的可以了解一下2022-05-05
實(shí)例分享cmake編譯一個(gè)簡(jiǎn)單c++項(xiàng)目(demo)
下面通過一個(gè)小例子來說明cmake編譯一個(gè)c++項(xiàng)目,生成可執(zhí)行文件,需要的朋友可以參考下2020-02-02
C/C++實(shí)現(xiàn)獲取系統(tǒng)時(shí)間的示例代碼
C 標(biāo)準(zhǔn)庫(kù)提供了 time() 函數(shù)與 localtime() 函數(shù)可以獲取到當(dāng)前系統(tǒng)的日歷時(shí)間。本文將通過一些簡(jiǎn)單的示例為大家講講C++獲取系統(tǒng)時(shí)間的具體方法,需要的可以參考一下2022-12-12
C++ LeetCode1775通過最少操作次數(shù)使數(shù)組和相等
這篇文章主要為大家介紹了C++ LeetCode1775通過最少操作次數(shù)使數(shù)組和相等,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
詳解C++數(shù)組和數(shù)組名問題(指針、解引用)
這篇文章主要介紹了詳解C++數(shù)組和數(shù)組名問題(指針、解引用),指針的實(shí)質(zhì)就是個(gè)變量,它跟普通變量沒有任何本質(zhì)區(qū)別,指針本身是一個(gè)對(duì)象,同時(shí)指針無需在定義的時(shí)候賦值,具體內(nèi)容詳情跟隨小編一起看看吧2021-09-09

