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í),編譯器會自動(dòng)生成以下6個(gè)默認(rèn)成員函數(shù)
:
默認(rèn)成員函數(shù)
:如果用戶沒有手動(dòng)實(shí)現(xiàn),則編譯器會自動(dòng)生成
的成員函數(shù)構(gòu)造函數(shù)
:主要完成初始化
工作;析構(gòu)函數(shù)
:主要完成清理
工作;拷貝構(gòu)造
:使用一個(gè)同類的對象初始化創(chuàng)建一個(gè)對象;賦值重載
:把一個(gè)對象賦值
給另一個(gè)對象;取地址重載
:普通對象
取地址操作;取地址重載
(const):const對象
取地址操作;
本章我們將學(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對象(之前叫作定義一個(gè)stack類型的變量)后,首先得調(diào)用它的專屬初始化函數(shù)StackInit
來初始化對象。
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)建對象,而是初始化對象
。
構(gòu)造函數(shù)之所以特殊,是因?yàn)橄啾扔谄渌蓡T函數(shù),它具有如下特性
:
- 函數(shù)名與類名相同;
- 無返回值;
- 對象實(shí)例化時(shí),編譯器
自動(dòng)調(diào)用
對應(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)建對象時(shí)編譯器會自動(dòng)調(diào)用構(gòu)造函數(shù),若是
調(diào)用無參構(gòu)造函數(shù)
,則無需在對象后面使用()
。否則會產(chǎn)生歧義:編譯器無法確定你是在聲明函數(shù)還是在創(chuàng)建對象
。
??錯(cuò)誤示例??
//錯(cuò)位示例 Date d3();
- 如果類中沒有顯式定義構(gòu)造函數(shù),則C++編譯器會自動(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ù),對內(nèi)置類型成員不作處理;對自定義類型成員,會調(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ù)對內(nèi)置類型??
class Date { public: //此處不對構(gòu)造函數(shù)做顯示定義,測試默認(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ù)的確未對內(nèi)置類型做處理。
??默認(rèn)構(gòu)造函數(shù)對自定義類型??
class stack { public: //此處對stack構(gòu)造函數(shù)做顯示定義 stack() { cout <<"stack()" << endl; _a = nullptr; _top = _capacity = 0; } private: int* _a; int _top; int _capacity; }; class queue { public: //此處不對queue構(gòu)造函數(shù)做顯示定義,測試默認(rèn)構(gòu)造函數(shù) /*queue() {}*/ private: //自定義類型成員 stack _s; }; void TestQueue() { queue q; }
- 如圖所示,在創(chuàng)建
queue
對象時(shí),默認(rèn)構(gòu)造函數(shù)對自定義成員_s
做了處理,調(diào)用了它的默認(rèn)構(gòu)造函數(shù)stack()
。
這一波蜜汁操作讓很多C++使用者感到困惑與不滿,為什么要針對內(nèi)置類型和自定義類型做不同的處理呢?終于,在C++11中針對內(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)值
:若不對成員變量做處理,則使用默認(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ù)是用來初始化對象的,析構(gòu)函數(shù)是用來銷毀對象
的。
- 需要注意的是,
析構(gòu)函數(shù)并不是對對象本身進(jìn)行銷毀
(因?yàn)榫植繉ο蟪隽俗饔糜驎孕袖N毀,由編譯器來完成),而是在對象銷毀時(shí)會自動(dòng)調(diào)用析構(gòu)函數(shù),對對象內(nèi)部的資源做清理
(例如stack _s中的int* a)。
同樣,有了析構(gòu)函數(shù),我們再也不用擔(dān)心創(chuàng)建對象(或定義變量)后由于忘記釋放內(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)會自動(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ù),對自定類型成員調(diào)用它的析構(gòu)函數(shù);
??舉例??
class stack { public: //此處對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: //此處不對queue構(gòu)造函數(shù)做顯示定義,測試默認(rèn)構(gòu)造函數(shù) /*queue() {}*/ private: //自定義類型成員 stack _s; }; void TestQueue1() { queue q; }
- 這里可能有小伙伴會好奇:
為什么析構(gòu)函數(shù)不像構(gòu)造函數(shù)那樣區(qū)分內(nèi)置類型與自定義類型呢
?
答案是:因?yàn)閮?nèi)置類型壓根不需要我們擔(dān)心清理工作,在其生命周期結(jié)束時(shí)會自動(dòng)銷毀。而自定義類型需要擔(dān)心,因?yàn)樽远x類型里可能含有申請資源(例如:malloc申請內(nèi)存須手動(dòng)釋放)。
- 如果類中沒有申請資源時(shí),析構(gòu)函數(shù)可以不寫,直接使用編譯器生成的默認(rèn)析構(gòu)函數(shù),比如
Date
類;有資源申請時(shí),一定要寫,否則會造成資源泄漏,比如stack
類。
到此這篇關(guān)于C++修煉之構(gòu)造函數(shù)與析構(gòu)函數(shù)的文章就介紹到這了,更多相關(guān)C語言 構(gòu)造函數(shù)與析構(gòu)函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言?智能指針?shared_ptr?和?weak_ptr
這篇文章主要介紹了C語言?智能指針?shared_ptr?和?weak_ptr,weak_ptr引入可以解決shared_ptr交叉引用時(shí)無法釋放資源的問題,下面來學(xué)習(xí)具體相關(guān)內(nèi)容吧,需要的朋友可以參考一下2022-04-04使用C語言實(shí)現(xiàn)繪制立體分離式環(huán)圖
這篇文章主要為大家詳細(xì)介紹了使用C語言實(shí)現(xiàn)繪制立體分離式環(huán)圖的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03C++實(shí)現(xiàn)LeetCode(161.一個(gè)編輯距離)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(161.一個(gè)編輯距離),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C語言詳解關(guān)鍵字sizeof與unsigned及signed的用法
這篇文章主要為大家詳細(xì)介紹了C語言關(guān)鍵字sizeof&&unsigned&&signed,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06