手機網(wǎng)站建設(shè) 豆丁關(guān)鍵詞挖掘長尾詞工具
? ? ??
本文已收錄至《C++語言》專欄!
作者:ARMCSKGT? ? ??
目錄
前言?
正文
構(gòu)造函數(shù)
對比C和C++的初始化
構(gòu)造函數(shù)的使用與特性
默認(rèn)構(gòu)造函數(shù)
C++11關(guān)于默認(rèn)構(gòu)造缺陷的補丁
析構(gòu)函數(shù)
析構(gòu)函數(shù)特性
默認(rèn)析構(gòu)和自定義析構(gòu)
拷貝構(gòu)造函數(shù)
問題聚焦?
拷貝構(gòu)造的定義和特性
使用場景
構(gòu)造函數(shù)小結(jié)
運算符重載
定義方式
特性
使用說明
運算符重載原理
賦值運算符重載
前后置++和--
const修飾this
取地址重載和const取地址重載
最后
前言?
C++類在設(shè)計之時,規(guī)定類中有六個默認(rèn)的成員函數(shù),這些成員函數(shù)天生就存在,而且功能都很強大,類和對象的關(guān)鍵點就在這六個默認(rèn)成員函數(shù)的學(xué)習(xí),本篇將會逐一介紹這六個成員函數(shù),讓我們向類和對象的深處出發(fā)!
正文
C++規(guī)定在每個類中有六個默認(rèn)函數(shù)成員:
函數(shù) 功能 重要性 構(gòu)造函數(shù) 定義和初始化成員變量 重要 析構(gòu)函數(shù) 釋放申請的內(nèi)存空間(銷毀成員變量) 重要 拷貝構(gòu)造(函數(shù)) 實現(xiàn)對象間的深拷貝 重要 賦值重載(函數(shù)) 實現(xiàn)對象間的深賦值 重要 取地址重載(函數(shù)) 自定義類對象取地址操作符功能 一般 const取地址重載(函數(shù)) 自定義對象取地址操作符功能const修飾返回的地址 一般 這些函數(shù)我們不寫,編譯器也會自己寫一個默認(rèn)的函數(shù)代替對應(yīng)函數(shù)!
//以日期類的方式初見六大默認(rèn)成員函數(shù)
class Date
{
public://構(gòu)造函數(shù)Date(size_t year = 1970, size_t month = 1, size_t day = 1){_year = year;_month = month;_day = day;}//析構(gòu)函數(shù)~Date(){_year = 0;_month = 0;_day = 0;}//拷貝構(gòu)造函數(shù)(簡稱:拷貝構(gòu)造)Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}//賦值重載函數(shù)(賦值運算符重載)Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}//取地址運算符重載Date* operator&(){return this;}//const返回取地址運算符重載,const修飾thisconst Date* operator&() const{return this;}private:size_t _year;size_t _month;size_t _day;};
構(gòu)造函數(shù)
對比C和C++的初始化
我們在使用C語言實現(xiàn)一些例如順序表,棧等簡單數(shù)據(jù)結(jié)構(gòu)時,一般都會寫一個初始化函數(shù)Init,防止野指針訪問,但這樣很容易讓我們忘記去調(diào)用!
?
在C++中,為了避免這種事情,引入了構(gòu)造函數(shù),在對象實例化時編譯器自動調(diào)用構(gòu)造函數(shù)進行初始化,所以構(gòu)造函數(shù)是為對象自動初始化而生的!
?
我們以日期對象為例,對比C與C++的初始化方案:
//C語言實現(xiàn)日期功能 typedef struct C_Date //日期數(shù)據(jù)結(jié)構(gòu)體 {size_t _year;size_t _month;size_t _day; }C_Date;void InitDate(C_Date* L)//初始化函數(shù) {L->_year = 0;L->_month = 0;L->_day = 0; }
//C++實現(xiàn)日期類 class CPP_Date //日期對象 { public://默認(rèn)構(gòu)造CPP_Date(size_t year){_year = year;_month = 1;_day = 1;}//重載實現(xiàn)多種默認(rèn)構(gòu)造方式CPP_Date(size_t year, size_t month, size_t day){_year = year;_month = month;_day = day;}private:size_t _year;size_t _month;size_t _day; };
可以發(fā)現(xiàn)C++中類融入構(gòu)造函數(shù)后只需要實例化對象就能同時完成初始化,非常方便!而且結(jié)合C++的缺少參數(shù),函數(shù)重載等新特性,可以讓初始化豐富多樣,增強程序可用性!
??
對比C與C++,可以發(fā)現(xiàn)C++非常貼心,就像汽車中的手動擋與自動擋,但兩者在不同場合各有千秋,在程序開發(fā)上C++的更勝一籌,在較為底層且需要更細(xì)節(jié)的程序控制時C語言更勝一籌!不過一般在程序開發(fā)中,C與C++可以搭配一起編程!
構(gòu)造函數(shù)的使用與特性
構(gòu)造函數(shù)是一個特殊的成員函數(shù),名字與類名相同,創(chuàng)建類類型對象時由編譯器自動調(diào)用,以保證每個數(shù)據(jù)成員都有 一個合適的初始值,并且在對象整個生命周期內(nèi)只調(diào)用一次(實例化時被編譯器調(diào)用)。
?
構(gòu)造函數(shù)是特殊的成員函數(shù),需要注意的是,構(gòu)造函數(shù)雖然名稱叫構(gòu)造,但是構(gòu)造函數(shù)的主要任務(wù)并不是開空間創(chuàng)建對象,而是初始化對象成員變量。
?構(gòu)造函數(shù)的定義方式:
class Test { public: //構(gòu)造函數(shù)必須公開Test(參數(shù)) {} //構(gòu)造函數(shù)的函數(shù)名與類名相同且沒有返回值 };
構(gòu)造函數(shù)的特性
- 函數(shù)名與類名相同。
- 無返回值(不需要寫返回值類型,void也不需要寫)。
- 對象實例化時編譯器自動調(diào)用對應(yīng)的構(gòu)造函數(shù)。
- 構(gòu)造函數(shù)可以重載,支持多個構(gòu)造函數(shù),但是默認(rèn)的構(gòu)造函數(shù)只有一個。
使用構(gòu)造函數(shù)初始化日期對象:
//C++實現(xiàn)日期類 class CPP_Date //日期對象 { public://默認(rèn)構(gòu)造函數(shù)只允許出現(xiàn)一種顯示,如果定義全缺省就可以代替默認(rèn)構(gòu)造了//CPP_Date()//默認(rèn)構(gòu)造函數(shù)初始化-功能比較局限//{// _year = 0;// _month = 0;// _day = 0;//}//構(gòu)造函數(shù)可以重載實現(xiàn)多種構(gòu)造方式CPP_Date(size_t year){_year = year;_month = 1;_day = 1;}//一般使用全缺省值方式代替默認(rèn)構(gòu)造-智能方便CPP_Date(size_t year = 1970, size_t month = 1, size_t day = 1){_year = year;_month = month;_day = day;}private:size_t _year;size_t _month;size_t _day; };int main() {//CPP_Date d(); //注意:這種調(diào)用默認(rèn)構(gòu)造的方式是錯誤的,調(diào)用默認(rèn)構(gòu)造不需要加()CPP_Date d1;CPP_Date d2(2022);CPP_Date d3(2023,3,12);//可以通過調(diào)用不同的構(gòu)造函數(shù)實例化多個不同的對象 }
默認(rèn)構(gòu)造函數(shù)
如果類中沒有顯式定義構(gòu)造函數(shù),則C++編譯器會自動生成一個無參的默認(rèn)構(gòu)造函數(shù),一旦
用戶顯式定義編譯器將不再生成。那有人可能會問,既然編譯器會自動生成構(gòu)造函數(shù),我們?yōu)槭裁催€要去寫?
注意:編譯器生成的默認(rèn)構(gòu)造函數(shù),對內(nèi)置類型不做處理,對自定義類型會調(diào)用該對象的構(gòu)造函數(shù)!
數(shù)據(jù)類型區(qū)分
- 內(nèi)置類型:int,char,double等。
- 自定義類型:struct,class等,這些自定義類型可以有自己的默認(rèn)構(gòu)造函數(shù)。
編譯器默認(rèn)構(gòu)造對內(nèi)置類型的初始化:?
編譯器默認(rèn)構(gòu)造初始化內(nèi)置類型 自定義默認(rèn)構(gòu)造:
//C++實現(xiàn)日期類 class CPP_Date //日期對象 { public://無參構(gòu)造函數(shù)//CPP_Date()//{// _year = 0;// _month = 0;// _day = 0;//}//全缺省默認(rèn)構(gòu)造CPP_Date(size_t year = 1970, size_t month = 1, size_t day = 1){_year = year;_month = month;_day = day;}//當(dāng)存在兩種實例化相同的構(gòu)造方法時,只能存在一種,否則在調(diào)用時會出錯!//例如 (CPP_Date d;) 編譯器無法判斷d對象調(diào)用的是哪一個構(gòu)造函數(shù)private:size_t _year;size_t _month;size_t _day; };
自定義默認(rèn)構(gòu)造完成內(nèi)置類型的初始化 ??
無參的構(gòu)造函數(shù)和全缺省的構(gòu)造函數(shù)都稱為默認(rèn)構(gòu)造函數(shù),并且默認(rèn)構(gòu)造函數(shù)只能有一個。
?
注意:無參構(gòu)造函數(shù)、全缺省構(gòu)造函數(shù)、我們沒寫編譯器默認(rèn)生成的構(gòu)造函數(shù),都可以認(rèn)為是默認(rèn)構(gòu)造函數(shù)。C++11關(guān)于默認(rèn)構(gòu)造缺陷的補丁
為了解決內(nèi)置類型無法被編譯器生成的默認(rèn)構(gòu)造初始化的問題,在C++11中支持內(nèi)置類型在聲明階段給缺省值,當(dāng)編譯器生成默認(rèn)構(gòu)造函數(shù)時,使用這些缺省值初始化內(nèi)置類型。
class CPP_Date //日期對象 { public:private:size_t _year = 1970; //聲明階段賦予缺省值size_t _month = 1;size_t _day = 1;//注意:類成員變量定義在構(gòu)造函數(shù)的初始化列表,并不是在聲明階段! };
所以,對于內(nèi)置類型要么自定義默認(rèn)構(gòu)造函數(shù),或者在聲明時賦予缺省值,對于自定義類型編譯器會調(diào)用對應(yīng)的構(gòu)造函數(shù)!
析構(gòu)函數(shù)
我們在寫順序表時,在結(jié)束使用時需要調(diào)用銷毀函數(shù)是否內(nèi)存空間,但是我們可能經(jīng)常也會忘記釋放空間,析構(gòu)函數(shù)就是用來銷毀對象和釋放空間的!
??
析構(gòu)函數(shù)是特殊的成員函數(shù),其功能與構(gòu)造函數(shù)相反,析構(gòu)函數(shù)不是完成對對象本身的銷毀,局部對象銷毀工作是由編譯器完成的。而對象在銷毀時(生命周期結(jié)束時)會自動調(diào)用析構(gòu)函數(shù),完成對象中資源的清理工作。
析構(gòu)函數(shù)特性
- 析構(gòu)函數(shù)名是在類名前加上字符 ~。
- 無參數(shù)無返回值類型(void也不需要寫)。
- 一個類只能有一個析構(gòu)函數(shù)。若未顯式定義,系統(tǒng)會自動生成默認(rèn)的析構(gòu)函數(shù)。
- 析構(gòu)函數(shù)不能重載。
- 對象生命周期結(jié)束時,C++編譯系統(tǒng)系統(tǒng)自動調(diào)用析構(gòu)函數(shù)。
? ?對于析構(gòu)函數(shù),最大的特性是在對象生命周期結(jié)束時被自動調(diào)用,與構(gòu)造函數(shù)的區(qū)別在于不支持重載,也就是說一個對象只能有一個析構(gòu)函數(shù)!
默認(rèn)析構(gòu)和自定義析構(gòu)
??
如果我們不寫析構(gòu)函數(shù),編譯器也會默認(rèn)生成,但編譯器生成的析構(gòu)函數(shù)對內(nèi)置類型仍然不做處理,對自定義類型會調(diào)用對應(yīng)的析構(gòu)函數(shù)處理!
?
//析構(gòu)函數(shù)定義 class Test {~Test() {//釋放方法} };
//簡易棧對象 typedef int DataType; class Stack { public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申請空間失敗!!!");return;}_capacity = capacity;_size = 0;cout << "構(gòu)造函數(shù)初始化棧對象" << endl;}void Push(DataType data){// CheckCapacity();_array[_size] = data;_size++;}// 其他方法...~Stack(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}cout << "析構(gòu)函數(shù)釋放棧對象空間" << endl;} private:DataType* _array;int _capacity;int _size; };
對于自定義類型和內(nèi)置類型,是否存在析構(gòu)函數(shù)進行釋放影響都不大,當(dāng)涉及我們自己動態(tài)開辟空間時,就需要使用析構(gòu)函數(shù)釋放空間!
注意:創(chuàng)建哪個類的對象則調(diào)用該類的析構(gòu)函數(shù),銷毀那個類的對象則調(diào)用該類的析構(gòu)函數(shù)!對于析構(gòu)函數(shù),只要是對象中涉及動態(tài)內(nèi)存申請,則需要使用析構(gòu)函數(shù)釋放!
拷貝構(gòu)造函數(shù)
拷貝構(gòu)造也是構(gòu)造函數(shù)的一種,但是參數(shù)不同則構(gòu)成重載,功能和特性與構(gòu)造函數(shù)不同!
問題聚焦?
我們在創(chuàng)建對象時,如果需要拷貝一個一模一樣的對象,也就是復(fù)制一個對象;那么就需要創(chuàng)建一個一模一樣的對象后將數(shù)據(jù)拷貝一份過去。
編譯器默認(rèn)生成的拷貝構(gòu)造函數(shù)只支持淺拷貝,也就是值拷貝,對于內(nèi)置類型,淺拷貝是沒有影響的,但是如果對象中申請了空間,那么該對象中必定有一個指針指向該空間的首地址,淺拷貝只會講該地址拷貝一份給另一個對象,那么會導(dǎo)致一個嚴(yán)重的問題,就是兩個對象申請的空間是同一個地址,在增刪查改和析構(gòu)時拷貝的對象析構(gòu)函數(shù)會對同一片空間進行修改和重復(fù)釋放一片空間導(dǎo)致異常,最后成為野指針問題!
淺拷貝只是簡單的逐字節(jié)拷貝,對于對象內(nèi)部有空間申請的,會發(fā)生共用空間重復(fù)析構(gòu)的情況;而深拷貝是在新對象中開辟一塊屬于自己的新空間,然后將數(shù)據(jù)逐一拷貝過來,新舊對象之間的數(shù)據(jù)相互獨立!
?
淺拷貝下對象共用一塊空間
拷貝構(gòu)造的定義和特性
??
拷貝構(gòu)造函數(shù):只有單個形參,該形參是對本類類型對象的引用(一般常用const修飾),在用已存在的類類型對象創(chuàng)建新對象時由編譯器自動調(diào)用。
? ?
特性
- 拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)的一個重載形式。
- 拷貝構(gòu)造函數(shù)的參數(shù)只有一個且必須是類類型對象的引用,使用傳值方式編譯器直接報錯,因為會引發(fā)無窮遞歸調(diào)用。
?定義和調(diào)用
class Test {//拷貝構(gòu)造形參的定義方式是唯一的:(const 類型& )Test(const Test& T) {//拷貝方法} //定義方式 };int main() {Test t1;Test t2(t1); //調(diào)用拷貝構(gòu)造方式一Test t3 = t2; //調(diào)用拷貝構(gòu)造方式二return 0; }
? ?
定義須知
- 編譯器默認(rèn)生成的拷貝構(gòu)造,只是簡單拷貝,只能用于非動態(tài)內(nèi)存開辟的空間
- 拷貝構(gòu)造的參數(shù)定義方式是唯一的??
- 拷貝構(gòu)造函數(shù)函數(shù)名與構(gòu)造函數(shù)相同,不過參數(shù)類型為類對象的引用,不加引用則會發(fā)生無窮拷貝(因為形參是拷貝而來的,這樣形參會陷入無限遞歸拷貝形參)
形參無窮遞歸拷貝 使用場景
//日期類示例 class Date { public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// Date(const Date& d) // 正確寫法Date(const Date& d) // 錯誤寫法:編譯報錯,會引發(fā)無窮遞歸{_year = d._year;_month = d._month;_day = d._day;} private:int _year;int _month;int _day; };int main() {Date d1;Date d2(d1); //拷貝構(gòu)造方式一Date d3 = d2; //拷貝構(gòu)造方式二return 0; }
像日期類這樣沒有動態(tài)內(nèi)存申請的對象,使用編譯器默認(rèn)生成的拷貝構(gòu)造進行淺拷貝即可,但是向數(shù)據(jù)結(jié)構(gòu)需要動態(tài)內(nèi)存申請等相對復(fù)雜的對象,就需要自定義拷貝構(gòu)造實現(xiàn)深拷貝!
? ??
拷貝構(gòu)造函數(shù)典型調(diào)用場景
- 使用已存在對象創(chuàng)建新對象
- 函數(shù)參數(shù)類型為類類型對象
- 函數(shù)返回值類型為類類型對象
說明
- 對于深拷貝,是有一定代價的,為了提高程序效率,一般對象傳參時,盡量使用引用類型,返回時根據(jù)實際場景,能用引用盡量使用引用!
- 默認(rèn)拷貝構(gòu)造函數(shù)與默認(rèn)構(gòu)造函數(shù)名相同,當(dāng)我們只寫拷貝而不寫構(gòu)造時,編譯器就會報錯,因為此時的拷貝會被誤以為是默認(rèn)構(gòu)造函數(shù)也就是說,默認(rèn)拷貝構(gòu)造函數(shù)存在的前提是默認(rèn)構(gòu)造函數(shù)已存在。
構(gòu)造函數(shù)小結(jié)
構(gòu)造大家族到這里基本內(nèi)容就介紹的差不多了!
類型 用途 處理情況 構(gòu)造函數(shù) 初始化對象 不對內(nèi)置類型作處理,自定義類型調(diào)用對應(yīng)構(gòu)造函數(shù) 析構(gòu)函數(shù) 銷毀對象 也不對內(nèi)置類型作處理,自定義類型調(diào)用對應(yīng)析構(gòu)函數(shù) 拷貝構(gòu)造函數(shù) 拷貝對象 只能對簡單內(nèi)置類型做處理,自定義類型需要自己實現(xiàn)深拷貝
運算符重載
C++為了增強代碼的可讀性引入了運算符重載,運算符重載是具有特殊函數(shù)名的函數(shù),也具有其返回值類型,函數(shù)名字以及參數(shù)列表,其返回值類型與參數(shù)列表與普通的函數(shù)類似。
運算符重載的引入,主要是為了解決基本運算符功能不足以滿足自定義類型需求的情況,例如日期類的加減,以及前后置++和--等,需要自定義對象運算符的功能!
定義方式
返回值類型 operator操作符(參數(shù)) {//自定義操作符功能 }// operator 是運算符重載的關(guān)鍵字
特性
不能通過連接其他符號來創(chuàng)建新的操作符:比如operator@
重載操作符必須有一個類類型參數(shù)
用于內(nèi)置類型的運算符,其含義不能改變,例如:內(nèi)置的整型+,不 能改變其含義
作為類成員函數(shù)重載時,其形參看起來比操作數(shù)數(shù)目少一個,因為成員函數(shù)的第一個參數(shù)為隱藏的this
對于內(nèi)置運算符,不能改變其含義
?operator操作符 就是函數(shù)名
注意這5個運算符不能重載:(1)?.*?,(2)?:: ,(3)sizeof,(4)?:,(5)?.?
//日期類 class Date { public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//為了保證封裝性,類成員變量一般是私有,所以運算符重載一般定義在類內(nèi)部bool operator==(const Date& d){//這里相當(dāng)于 *this 與 d 的 == 比較return _year == d._year&& _month == d._month&& _day == d._day;}private:int _year;int _month;int _day; };int main() {Date d1(2018, 9, 26);Date d2(2018, 9, 27);cout << (d1 == d2) << endl; //這里相當(dāng)于調(diào)用 d1.operator==(d2)return 0; }
使用說明
- operator 函數(shù)中的操作數(shù)取決于參數(shù)個數(shù)
- operator 一般定義在類中,方便訪問類成員,當(dāng)定義在類中時,運算符左邊的對象默認(rèn)是*this
- operator 如果定義在類外,則無法訪問類的所有成員,此時要么在類中定義特定函數(shù)獲取私有成員要么聲明為友元函數(shù),但是大部分場景下都沒有定義在類中更合適
運算符重載原理
運算符重載的原理與函數(shù)重載原理基本相同,也是對函數(shù)名修飾。
如果定義在類中在Linux環(huán)境下修飾規(guī)則為:_ZN4D+類名+運算符英文簡稱+ERKS_
賦值運算符重載
通過上面的鋪墊,我們就要介紹下一個默認(rèn)成員,那就是賦值重載函數(shù)!
class Test {};
賦值重載是將一個對象賦值給另一個對象,與拷貝構(gòu)造相似,但是拷貝構(gòu)造是通過一個對象去實例化一個相同的對象,而賦值重載的前提是兩個對象已經(jīng)實例化存在,相互之間再賦值!本質(zhì)區(qū)別在于:一個是對象尚未實例化,另一個是兩個對象都已存在!當(dāng)兩個對象都被創(chuàng)建,并發(fā)生賦值行為時,才叫做賦值重載!
??
對于這種自定義類型復(fù)制的問題,就會涉及深拷貝和淺拷貝的問題,所以賦值重載是很有必要的!
//日期類 class Date { public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}Date& operator=(const Date& d) //與拷貝構(gòu)造一樣能用引用就用引用{if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this; //返回賦值的對象的引用(也就是自己)//這里之所以返回自己的引用是因為會發(fā)生 d1 = d2 = d3 這樣連等的情況//使用引用可以有效避免拷貝}private:int _year;int _month;int _day; };
賦值運算符重載格式
- 參數(shù)類型:const T&,傳遞引用可以提高傳參效率
- 返回值類型:T&,返回引用可以提高返回的效率,有返回值目的是為了支持連續(xù)賦值
- 檢測是否自己給自己賦值
- 返回*this :要復(fù)合連續(xù)賦值的含義
- 賦值運算符只能重載成類的成員函數(shù)不能重載成全局函數(shù)
如果賦值運算符重載成全局函數(shù),就沒有this指針了,需要給兩個參數(shù),而且此時編譯器就會報錯error C2801: “operator =”必須是非靜態(tài)成員!
??
原因:賦值運算符如果不顯式實現(xiàn),編譯器會生成一個默認(rèn)的。此時用戶再在類外自己實現(xiàn)一個全局的賦值運算符重載,就和編譯器在類中生成的默認(rèn)賦值運算符重載沖突了,故賦值運算符重載只能是類的成員函數(shù)。
?默認(rèn)賦值重載函數(shù):用戶沒有顯式實現(xiàn)時,編譯器會生成一個默認(rèn)賦值運算符重載,以值的方式逐字節(jié)拷貝。
??
注意:內(nèi)置類型成員變量是直接賦值的,而自定義類型成員變量需要調(diào)用對應(yīng)類的賦值運算符重載完成賦值。
??
所以賦值重載的使用環(huán)境與拷貝構(gòu)造類似:如果類中未涉及到動態(tài)內(nèi)存申請(資源管理),賦值運算符是否實現(xiàn)都可以;一旦涉及到資源管理則必須要實現(xiàn)!
//棧對象 - 猜猜是否會發(fā)生與拷貝構(gòu)造相同的問題 typedef int DataType; class Stack { public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申請空間失敗");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}} private:DataType* _array;size_t _size;size_t _capacity; };int main() {Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2;s2 = s1;return 0; }
前后置++和--
對于自定義對象,前后置++和--還是經(jīng)常會使用到的!
class Test {Test& operator++() {} //前置++Test operator++(int) {} //后置++Test& operator--() {} //前置--Test operator--(int) {} //后置-- };
//以日期類進行介紹 class Date { public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// 前置++:返回+1之后的結(jié)果 // 注意:this指向的對象函數(shù)結(jié)束后不會銷毀,故以引用方式返回提高效率Date& operator++(){_day += 1;return *this;}// 后置++: // 注意:后置++是自己+1然后返回+1之前的值 // 而temp是臨時對象,因此只能以值的方式返回,不能返回引用Date operator++(int){Date temp(*this);_day += 1;return temp;} private:int _year;int _month;int _day; };int main() {Date d1;d1++;++d1;return 0; }
原理:前置++和后置++都是一元運算符,為了讓前置++與后置++形成能正確重載,C++規(guī)定:后置++重載時多增加一個int類型的參數(shù),但調(diào)用函數(shù)時該參數(shù)不用傳遞,編譯器自動傳遞(前后置--實現(xiàn)與++相同)。
const修飾this
將const修飾的“成員函數(shù)”稱之為const成員函數(shù),const修飾類成員函數(shù),實際修飾該成員函數(shù)隱含的this指針,表明在該成員函數(shù)中不能對類的任何成員進行修改。
?
const常被用來修飾引用和指針,使用const修飾可以提高程序的健壯性!
使用場景
- 被(指針)指向?qū)ο笫浅A粱蚺R時變量
- 被引用對象是常亮或臨時變量
這些對象必須使用const修飾,避免權(quán)限放大的問題!
修飾this指針格式
有小伙伴可能會疑惑,this指針我們不能顯示定義,那么如果要const修飾怎么辦?
對于this指針的修飾,格式為:
class Test {void Fun() const //將const加在函數(shù)參數(shù)后即可{//函數(shù)方法} };
//設(shè)想以下日期類代碼的運行結(jié)果 class Date { public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << "Print()" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;}void Print() const{cout << "Print()const" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;} private:int _year; // 年int _month; // 月int _day; // 日 };int main() {Date d1(2022, 1, 13);d1.Print();const Date d2(2022, 1, 13);d2.Print();return 0; }
代碼運行結(jié)果 總之,const修飾this指針可以起到權(quán)限平移的作用!
取地址重載和const取地址重載
這兩個默認(rèn)成員函數(shù)一般不用重新定義 ,編譯器默認(rèn)會生成。
class Date { public:Date* operator&() //返回對象的地址{return this;}const Date* operator&() const //返回const修飾對象的地址{return this;} private:int _year; // 年int _month; // 月int _day; // 日 };
這兩個運算符一般不需要重載,使用編譯器生成的默認(rèn)取地址的重載即可,只有特殊情況,才需要重載,比如想讓別人獲取到指定的內(nèi)容!
最后
以上就是 類和對象 - 中 的全部內(nèi)容了,本篇介紹了類的六大默認(rèn)成員函數(shù),對于構(gòu)造函數(shù)何時用編譯器自動生成的,何時自己實現(xiàn)都需要依照情況而定!對于每個成員其規(guī)則和細(xì)節(jié)都很多,需要我們在長期的使用中去牢固的掌握,掌握了這六大成員函數(shù)的使用,那么你將對類和對象的掌握又進一步!
本次 <C++類和對象 - 中> 就介紹到這里啦,希望能夠盡可能幫助到大家。
如果文章中有瑕疵,還請各位大佬細(xì)心點評和留言,我將立即修補錯誤,謝謝!
🌟其他文章閱讀推薦🌟
C++ 類和對象 - 上
C++ 入門知識
數(shù)據(jù)結(jié)構(gòu)初階?<棧>
🌹歡迎讀者多多瀏覽多多支持!🌹