C++類中六個(gè)默認(rèn)的成員函數(shù)詳解
淺談
先來說一下“this指針”:
C++中通過引入this指針解決該問題,暨:C++編譯器給每個(gè)“非靜態(tài)的成員函數(shù)”增加了一個(gè)隱藏的指針參數(shù),讓該指針指向當(dāng)前對象(函數(shù)運(yùn)行時(shí)調(diào)用該函數(shù)的對象),在函數(shù)體中所有成員變量的操作,都是通過該指針去訪問,只不過所有的操作對用戶是透明的,暨用戶不需要來傳遞,編譯器自動(dòng)完成。
說了這么多其實(shí)編譯器在生成程序時(shí)獲取對象首地址的信息。然后將獲取的對象的首地址存放在了寄存器中,成員函數(shù)的其它參數(shù)都是存放在棧中。而this指針參數(shù)則是存放在寄存器中。類的靜態(tài)成員函數(shù)(用static修飾的成員函數(shù))因?yàn)闆]有this指針這個(gè)參數(shù),所以類的靜態(tài)成員函數(shù)也就無法調(diào)用類的非靜態(tài)成員變量。
構(gòu)造函數(shù)
構(gòu)造函數(shù)是一個(gè)特殊的成員函數(shù),名字與類名相同且不能有返回值,創(chuàng)建類類型時(shí)由編譯器自動(dòng)調(diào)用,在對象的生命周期內(nèi)只調(diào)用一次。**主要任務(wù)是初始化對象。
↓下面是一個(gè)簡單的構(gòu)造函數(shù)(全缺?。?/p>
主函數(shù)初始化時(shí)如果無參則以缺省值0給成員變量賦值。
默認(rèn)構(gòu)造函數(shù):
Q:為什么會出現(xiàn)上面的報(bào)錯(cuò)——包含多個(gè)默認(rèn)構(gòu)造函數(shù)?
A:無參的構(gòu)造函數(shù)和全缺省的構(gòu)造函數(shù)都稱為默認(rèn)構(gòu)造函數(shù),并且默認(rèn)構(gòu)造函數(shù)只能有一個(gè)。注意:無參構(gòu)造函數(shù),全缺省構(gòu)造函數(shù),我們沒寫編譯器默認(rèn)生成的構(gòu)造函數(shù),都可以稱為默認(rèn)構(gòu)造函數(shù)。
特征:
1.函數(shù)名與類名相同;
2.無返回值;
3.對象實(shí)例化時(shí)編譯器自動(dòng)調(diào)用對應(yīng)的構(gòu)造函數(shù);
4.構(gòu)造函數(shù)可以重載。
析構(gòu)函數(shù)
析構(gòu)函數(shù):與構(gòu)造函數(shù)功能相反,析構(gòu)函數(shù)是完成對象的銷毀,局部對象銷毀工作是由編譯器完成的。而對象在銷毀時(shí)會自動(dòng)調(diào)用析構(gòu)函數(shù),完成類的一些資源清理工作,和構(gòu)造函數(shù)一樣,如果我們沒寫析構(gòu)函數(shù),系統(tǒng)會生成一個(gè)默認(rèn)析構(gòu)函數(shù),但這個(gè)析構(gòu)函數(shù)什么都不會做。
如果類中的成員變量不需要?jiǎng)討B(tài)開辟內(nèi)存空間,則默認(rèn)析構(gòu)函數(shù)可以完成析構(gòu)任務(wù),比如下面這種,可以說不用析構(gòu)。
但是像下面這種,默認(rèn)析構(gòu)函數(shù)已經(jīng)不能夠完成
特征:
1.函數(shù)名是在類名前加上字符~;
2.無參數(shù)(有一個(gè)隱藏參數(shù)*this指針)無返回值;
3.一個(gè)類有且僅有一個(gè)析構(gòu)函數(shù),若未顯示定義,系統(tǒng)會自動(dòng)生成默認(rèn)的析構(gòu)函數(shù);
4.對象生命周期結(jié)束時(shí),C++編譯系統(tǒng)自動(dòng)調(diào)用析構(gòu)函數(shù)。
拷貝構(gòu)造函數(shù)
拷貝構(gòu)造函數(shù):只有單個(gè)形參,該形參是對本類類型對象的引用(一般常用const修飾),在用已存在的類類型對象創(chuàng)建新對象時(shí)由編譯器自動(dòng)調(diào)用。
從上圖我們可以看出,關(guān)于給t2變量初始化時(shí)肯定不是調(diào)用構(gòu)造函數(shù)。
下面這張圖應(yīng)該就可以解釋上面的問題
關(guān)于對拷貝構(gòu)造函數(shù)參數(shù)的說明:
當(dāng)然也同構(gòu)造函數(shù)一樣,若未顯示定義,系統(tǒng)生成默認(rèn)的拷貝構(gòu)造函數(shù)。默認(rèn)的拷貝構(gòu)造函數(shù)對象按內(nèi)存存儲按字節(jié)序完成拷貝,暨淺拷貝或值拷貝。
特征:
1.拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)的一個(gè)重載形式;
2.拷貝構(gòu)造函數(shù)的參數(shù)只有一個(gè)(當(dāng)然還有個(gè)隱藏的*this)且必須使用引用傳參,使用傳值方式會引發(fā)死遞歸。
賦值重載函數(shù)
賦值重載函數(shù):C++為了增強(qiáng)代碼的可讀性引入了運(yùn)算符重載,運(yùn)算符重載是具有特殊函數(shù)名的函數(shù),也具有其返回值類型,函數(shù)名字以及參數(shù)列表,其返回值類型與普通的函數(shù)類似。
**函數(shù)名字為:**關(guān)鍵字operator后面接需要重載的運(yùn)算符符號;
函數(shù)原型:返回值類型operator操作符(參數(shù)列表)
Test& operator= (const Test& t)
注意:
不能通過連接其他符號來創(chuàng)建新的操作符:比如operator@;
重載操作符必須有一個(gè)類類型或者枚舉類型的操作數(shù);
用于內(nèi)置類型的操作符的操作符,其含義不能改變,例如:內(nèi)置的整型+,不能改變其含義;
作為類成員的重載函數(shù)時(shí),其形參看起來比操作數(shù)數(shù)目少1成員函數(shù)的,操作符有一個(gè)默認(rèn)的形參this,限定為第一個(gè)形參;
*、::、sizeof、?:、. 以上5個(gè)運(yùn)算符不能重載。
一個(gè)類如果沒有顯示定義賦值運(yùn)算符重載,編譯器也會生成一個(gè),完成對象按字節(jié)序的值拷貝。
const成員函數(shù)
將const修飾的類成員函數(shù)稱之為const成員函數(shù),const修飾類成員函數(shù),實(shí)際修飾該成員函數(shù)隱含的this指針,表明該成員函數(shù)中不能對類的任何成員進(jìn)行修改。
multable關(guān)鍵字:當(dāng)有必須要修改的成員變量時(shí),需在成員變量聲明時(shí)前加上該關(guān)鍵字,及時(shí)是const成員函數(shù)也依然可以修改。
取地址及const取地址重載函數(shù)
這兩個(gè)默認(rèn)成員函數(shù)一般不用重新定義,編譯器默認(rèn)生成;
class Date { public: Date* operator&() { return this; } //因?yàn)閷ο蟊籧onst修飾不能更改,所以返回值也要被const修飾 const Date* operator&() const { return this; } private: int _year; int _month; int _day; };
深挖
構(gòu)造函數(shù)
上面的代碼居然可以正常運(yùn)行并且賦值成功,這是為什么。實(shí)際上編譯器在執(zhí)行賦值語句前,將“100作為參數(shù)來構(gòu)造一個(gè)無名的臨時(shí)的類”然后進(jìn)行賦值。
上面這種情況我們稱為**“隱式轉(zhuǎn)換”**。
explicit關(guān)鍵字:如果在構(gòu)造函數(shù)前加上這個(gè)關(guān)鍵字,則要求顯示轉(zhuǎn)換,不能進(jìn)行隱式轉(zhuǎn)換。
因此我們進(jìn)行強(qiáng)轉(zhuǎn)之后再賦值;
我們換一種思路,將“類”給整型賦值,且先給出一個(gè)強(qiáng)轉(zhuǎn)函數(shù);
最后介紹另外一種初始化的方式:
給出一個(gè)復(fù)數(shù)類,參數(shù)列表初始化的效率要高于第一種初始化方式。
拷貝構(gòu)造函數(shù)
下面介紹一下深拷貝,先看下面一段代碼:
這個(gè)代碼中我們沒有寫拷貝構(gòu)造函數(shù),可見默認(rèn)拷貝函數(shù)這里出了問題;前面我們說過,默認(rèn)拷貝方式是淺拷貝,也就是值拷貝。
上面s1使用hello初始化,s2使用s1的值來拷貝,因此s2并未開辟新空間,而是指向s1的空間,因此在最后調(diào)用析構(gòu)函數(shù)的時(shí)候,對同一塊空間free了兩次。
如果將代碼改成下面這種,那么就不會報(bào)錯(cuò)。
賦值運(yùn)算符重載函數(shù)
這里我們繼續(xù)引用上面構(gòu)造函數(shù)部分最后給出的那個(gè)復(fù)數(shù)類
我們上面說了賦值重載函數(shù),那么到底什么是賦值運(yùn)算符重載呢?
運(yùn)算符重載:對運(yùn)算符賦予新的意義↓↓↓
由上圖可知,上面這個(gè)對加法運(yùn)算符符號“+”的重載函數(shù)是成員函數(shù),因?yàn)樗鼌?shù)里面有一個(gè)隱藏的的this指針,所以需要用對象來調(diào)動(dòng)它。
上面的代碼整體的思路就是:
1.調(diào)用四次次構(gòu)造函數(shù),構(gòu)造C1C2C3以及在operator+內(nèi)部的tmp;
2.C1調(diào)用加法重載函數(shù)進(jìn)行C1+C2;
3.加法重載函數(shù)返回時(shí)需要調(diào)動(dòng)一次拷貝構(gòu)造函數(shù)(tmp拷貝到臨時(shí)對象);
4.調(diào)用賦值重載將C1+C2的值賦給C。
當(dāng)寫的類想做某種運(yùn)算時(shí),但編譯器不支持,因此我們需要對運(yùn)算符進(jìn)行重載。
總結(jié)
到此這篇關(guān)于C++類中六個(gè)默認(rèn)的成員函數(shù)詳解的文章就介紹到這了,更多相關(guān)C++類成員函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++類結(jié)構(gòu)體與json相互轉(zhuǎn)換
這篇文章主要介紹的是C++類結(jié)構(gòu)體與json相互轉(zhuǎn)換,json字符串一般使用的是開源的類庫Newtonsoft.Json,方法十分簡潔,下面就隨小編一起看下面文章內(nèi)容吧2021-09-09C語言對組文件處理的相關(guān)函數(shù)小結(jié)
這篇文章主要介紹了C語言對組文件處理的相關(guān)函數(shù)小結(jié),包括setgrent()函數(shù)和getgrent()函數(shù)以及endgrent()函數(shù),需要的朋友可以參考下2015-08-08