詳解C++之類和對(duì)象(2)
一.構(gòu)造函數(shù)
1.構(gòu)造函數(shù)的定義:
構(gòu)造函數(shù) 是一個(gè) 特殊的成員函數(shù),名字與類名相同 , 創(chuàng)建類類型對(duì)象時(shí)由編譯器自動(dòng)調(diào)用 ,保證每個(gè)數(shù)據(jù)成員都有 一個(gè)合適的初始值,并且 在對(duì)象的生命周期內(nèi)只調(diào)用一次 。 其實(shí)構(gòu)造函數(shù)的作用就是完成成員變量的初始化 ,但不同于c語(yǔ)言的初始化構(gòu)造函數(shù)可以實(shí)在創(chuàng)造對(duì)象的同時(shí)就完成成員變量的初始化。
2.構(gòu)造函數(shù)的特征:
1. 函數(shù)名與類名相同。
2. 無(wú)返回值。
3. 對(duì)象實(shí)例化時(shí)編譯器 自動(dòng)調(diào)用 對(duì)應(yīng)的構(gòu)造函數(shù)。
4. 構(gòu)造函數(shù)可以重載。
3.構(gòu)造函數(shù)的實(shí)現(xiàn):
構(gòu)造函數(shù)的實(shí)現(xiàn)主要有三種,
1.當(dāng)用戶沒(méi)有實(shí)現(xiàn)構(gòu)造函數(shù)的話系統(tǒng)會(huì)默認(rèn)創(chuàng)造一個(gè),此時(shí)系統(tǒng)會(huì)將內(nèi)置類型的成員變量賦予隨機(jī)值,而對(duì)于自定義類型的成員變量則會(huì)調(diào)用他們的構(gòu)造函數(shù)。(注:內(nèi)置類型一般指的是:int char double float等這些定義好的類型,自定義類型指的是:struct這種類型以及class類這種)。
2.當(dāng)然用戶也可以自己實(shí)現(xiàn)構(gòu)造函數(shù),一種為無(wú)參構(gòu)造
3.類一種為帶參構(gòu)造,但是在帶參構(gòu)造中我們使用全缺省構(gòu)造。我們用代碼展示一下:
3.1.系統(tǒng)默認(rèn)的構(gòu)造函數(shù)
我們可以看到當(dāng)我們沒(méi)有在Data類進(jìn)行函數(shù)構(gòu)造的時(shí)系統(tǒng)將會(huì)自己默認(rèn)創(chuàng)建構(gòu)造函數(shù),對(duì)內(nèi)置類型變量賦予隨機(jī)值,自定義類型調(diào)用自己的構(gòu)造函數(shù)(若自定義類型也沒(méi)有定義構(gòu)造函數(shù)那么此例子中的_a1和_a2也會(huì)被賦予隨機(jī)值)
3.2無(wú)參構(gòu)造
3.3 帶參構(gòu)造
這里出一個(gè)問(wèn)題對(duì)于代碼風(fēng)格造成的問(wèn)題:成員變量year最后的結(jié)果是多少呢?
class A{public:A(int year){year = year;}private:int year;};int main(){A a(20);}
答案是:隨機(jī)值。那么為什么是隨機(jī)值呢?這里主要是變量之間它采用了就近原則,所以等式左邊的year會(huì)直接尋找離他最近的變量所以會(huì)將等式右邊的year直接賦值給它自己,所以year最后的值就是隨機(jī)值。
我們繼續(xù)來(lái)說(shuō)帶參的構(gòu)造函數(shù),我們一般推薦使用的是全缺省的構(gòu)造函數(shù)(注:
無(wú)參的構(gòu)造函數(shù)和全缺省的構(gòu)造函數(shù)都稱為默認(rèn)構(gòu)造函數(shù),并且默認(rèn)構(gòu)造函數(shù)只能有一個(gè)。無(wú)參構(gòu)造函數(shù)、全缺省構(gòu)造函數(shù)、我們沒(méi)寫(xiě)編譯器默認(rèn)生成的構(gòu)造函數(shù),三者都可以認(rèn)為是默認(rèn)成員函數(shù)。
)
二 析構(gòu)函數(shù)
構(gòu)造函數(shù)時(shí)完成對(duì)象的初始化,那么一個(gè)對(duì)象又是怎么樣被銷毀的呢?
1.析構(gòu)函數(shù)的定義
與構(gòu)造函數(shù)功能相反,析構(gòu)函數(shù)不是完成對(duì)象的銷毀,局部對(duì)象銷毀工作是由編譯器完成的。而 對(duì)象在銷毀時(shí)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),完成類的一些清理工作。
2.析構(gòu)函數(shù)的特征
1. 析構(gòu)函數(shù)名是在類名前加上字符 ~ 。
2. 無(wú)參數(shù)無(wú)返回值。
3. 一個(gè)類有且只有一個(gè)析構(gòu)函數(shù)。若未顯式定義,系統(tǒng)會(huì)自動(dòng)生成默認(rèn)的析構(gòu)函數(shù) 。
4. 對(duì)象生命周期結(jié)束時(shí), C++ 編譯系統(tǒng)系統(tǒng)自動(dòng)調(diào)用析構(gòu)函數(shù)。
這里我們用棧的例子來(lái)說(shuō)明析構(gòu)函數(shù)的實(shí)現(xiàn)以及作用。
class Stack { public: Stack(int capacity = 4) { _a = (int*)malloc(sizeof(int)*capacity); if (_a == nullptr) { cout << "malloc fail" << endl; exit(-1); } _top = 0; _capacity = capacity; } //析構(gòu)函數(shù)的實(shí)現(xiàn) ~Stack() { // 像Stack這樣的類,對(duì)象中的資源需要清理工作,就用析構(gòu)函數(shù) free(_a); _a = nullptr; _top = _capacity = 0; } private: int* _a; int _top; int _capacity; };
這里是完成構(gòu)造函數(shù),有自己定義的析構(gòu)函數(shù)的效果。同構(gòu)造函數(shù)一樣對(duì)于內(nèi)置成員變量析構(gòu)函數(shù)會(huì)置為隨機(jī)值,而自定義類型則會(huì)去調(diào)用他們的析構(gòu)函數(shù)。
三 拷貝函數(shù)
如果某些時(shí)候我們需要去復(fù)制一個(gè)對(duì)象,這樣的話我們?cè)撛趺礃尤ソ鉀Q呢?
這里我們就需要引入拷貝函數(shù)。那么什么叫做拷貝函數(shù)呢?我們應(yīng)該去怎么實(shí)現(xiàn)呢?有什么注意事項(xiàng)呢?這里我們一一來(lái)說(shuō)道。
1.拷貝函數(shù)定義
構(gòu)造函數(shù) : 只有單個(gè)形參 ,該形參是對(duì)本 類類型對(duì)象的引用 ( 一般常用 const 修飾 ) ,在用 已存在的類類型對(duì)象 創(chuàng)建新對(duì)象時(shí)由編譯器自動(dòng)調(diào)用 。
2.拷貝函數(shù)的特性
1. 拷貝構(gòu)造函數(shù) 是構(gòu)造函數(shù)的一個(gè)重載形式 。
2. 拷貝構(gòu)造函數(shù)的參數(shù)只有一個(gè)且必須使用引用傳參,使用傳值方式會(huì)引發(fā)無(wú)窮遞歸調(diào)用 。
3. 若未顯示定義,系統(tǒng)生成默認(rèn)的拷貝構(gòu)造函數(shù)。 默認(rèn)的拷貝構(gòu)造函數(shù)對(duì)象按內(nèi)存存儲(chǔ)按字節(jié)序完成拷 貝,這種拷貝我們叫做淺拷貝,或者值拷貝。
3.拷貝函數(shù)的實(shí)現(xiàn)
拷貝函數(shù)的實(shí)現(xiàn)分為兩種一種是系統(tǒng)默認(rèn),一種是自己定義。我們分別來(lái)看其效果
class A { public: A() { _a1 = 1; _a2 = 2; } ~A() { cout << "A()" << endl; } private: int _a1; int _a2; }; class Data { public: /*Data() { _year = 2021; _month = 12; _day = 12; }*/ //Data(int year, int month, int day) //{ // _year = year; // _month = month; // _day = day; //} Data(int year = 2022, int month = 12, int day = 12) { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; A a; }; int main() { Data s; //拷貝函數(shù)的調(diào)用 Data s2(s); return 0; }
調(diào)用系統(tǒng)默認(rèn)生成拷貝函數(shù)(注:這里拷貝函數(shù)的拷貝對(duì)自定義類型和內(nèi)置類型的成員變量處理都是一致的完成字節(jié)序的值拷貝)
圖1 調(diào)用系統(tǒng)默認(rèn)生成的拷貝函數(shù)
圖2 調(diào)用用戶自己定義的拷貝函數(shù)
在這里我們順便說(shuō)一下在自定義拷貝函數(shù)的時(shí)候一定要使用引用不然會(huì)出現(xiàn)無(wú)限遞歸例如 Data(Data s){}正確的使用是Data (const Data & s){}其中const是為了保護(hù)原數(shù)據(jù)不被輕易改動(dòng)。
class A { public: A() { _a1 = 1; _a2 = 2; } ~A() { cout << "A()" << endl; } private: int _a1; int _a2; }; class Data { public: /*Data() { _year = 2021; _month = 12; _day = 12; }*/ //Data(int year, int month, int day) //{ // _year = year; // _month = month; // _day = day; //} Data( const Data &s) { _year = s._year; _month = s._month; _day = s._day; } Data(int year = 2023, int month = 12, int day = 12) { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; A a; }; int main() { Data s; //拷貝函數(shù)的調(diào)用 Data s2(s); return 0; }
我們可以發(fā)現(xiàn)s2均完整的賦值了s的內(nèi)容,但是這里真的就沒(méi)有問(wèn)題了嗎?如果我們使用系統(tǒng)默認(rèn)生成的拷貝函數(shù)成員變量中含有指針那么會(huì)出現(xiàn)什么樣的問(wèn)題呢?
class String { public: String(const char* str = "jack") { _str = (char*)malloc(strlen(str) + 1); strcpy(_str, str); } ~String() { cout << "~String()" << endl; free(_str); } private: char* _str; }; int main() { String s; String s1(s); }
我們可以看到雖然雖然s1拷貝了s的內(nèi)容但是最后系統(tǒng)還是拋出了錯(cuò)誤那么這個(gè)錯(cuò)誤來(lái)自那里呢?
我們看這幅圖
這里就是我們之前說(shuō)的系統(tǒng)默認(rèn)生成的拷貝函數(shù)是淺拷貝,那么怎么去完成深拷貝我們后邊在繼續(xù)講解。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++中內(nèi)存池的簡(jiǎn)單原理及實(shí)現(xiàn)詳解
內(nèi)存池的思想是,在真正使用內(nèi)存之前,預(yù)先申請(qǐng)分配一定數(shù)量、大小預(yù)設(shè)的內(nèi)存塊留作備用。本文主要來(lái)和大家聊聊內(nèi)存池的簡(jiǎn)單原理及實(shí)現(xiàn),希望對(duì)大家有所幫助2023-03-03深入解析C++編程中__alignof 與__uuidof運(yùn)算符的使用
這篇文章主要介紹了C++編程中__alignof 與__uuidof運(yùn)算符的使用,是C++入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2016-01-01C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12C++進(jìn)一步認(rèn)識(shí)類與對(duì)象
類是創(chuàng)建對(duì)象的模板,一個(gè)類可以創(chuàng)建多個(gè)對(duì)象,每個(gè)對(duì)象都是類類型的一個(gè)變量;創(chuàng)建對(duì)象的過(guò)程也叫類的實(shí)例化。每個(gè)對(duì)象都是類的一個(gè)具體實(shí)例(Instance),擁有類的成員變量和成員函數(shù)2021-10-10vscode調(diào)試gstreamer源碼的詳細(xì)流程
在本文中主要介紹了如何使用vscode調(diào)試C++和python程序,并進(jìn)一步分析了如何調(diào)試gstreamer源碼,講述了如何調(diào)試gstreamer源碼的具體流程,感興趣的朋友跟隨小編一起看看吧2023-01-01C/C++ 中堆和棧及靜態(tài)數(shù)據(jù)區(qū)詳解
這篇文章主要介紹了C/C++ 中堆和棧及靜態(tài)數(shù)據(jù)區(qū)詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04C語(yǔ)言超詳細(xì)講解指針與結(jié)構(gòu)體
指針提供了對(duì)地址操作的一種方法,因此,使用指針可使得C語(yǔ)言能夠更高效地實(shí)現(xiàn)對(duì)計(jì)算機(jī)底層硬件的操作。另外,通過(guò)指針可以更便捷地操作數(shù)組。C數(shù)組允許定義可存儲(chǔ)相同類型數(shù)據(jù)項(xiàng)的變量,結(jié)構(gòu)是C編程中另一種用戶自定義的可用的數(shù)據(jù)類型,它允許您存儲(chǔ)不同類型的數(shù)據(jù)項(xiàng)2022-05-05