C++入門淺談之類和對(duì)象
一、面向過程vs面向?qū)ο?/h2>
C語言面向過程,關(guān)注的是過程,分析出求解問題的步驟,通過函數(shù)調(diào)用逐步解決問題
C++是基于面向?qū)ο螅P(guān)注的是對(duì)象,將一件事情拆分成不同的對(duì)象,靠對(duì)象之間的交互完成,C++不是純面向?qū)ο蟮恼Z言,C++既有面向過程,也有面向?qū)ο罂梢曰旌暇幊?。C語言面向過程,數(shù)據(jù)和方法是分離的。CPP面向?qū)ο?,?shù)據(jù)和方法是封裝在一起的,如struct里即可用存數(shù)據(jù)也可以調(diào)用方法(函數(shù))
struct ListNodeCPP{ int val; ListNodeCPP* next; }; int main(){ //struct ListNodeCPP n1; 就不需要這樣調(diào)用了 ListNodeCPP n1; }
所以這里的struct已經(jīng)不僅僅是結(jié)構(gòu)體,在cpp中已經(jīng)升級(jí)成了類名
二、類的限定符及封裝
類包括成員變量和成員函數(shù)
下圖為類的訪問限定符及封裝
Warning:
在class中,如果不寫訪問限定符默認(rèn)是私有
在struct中,如果不寫訪問限定符默認(rèn)是公有
class類中的private里的成員變量前面都會(huì)加個(gè)下劃線因?yàn)樵诤瘮?shù)復(fù)制時(shí)更加容易區(qū)分
面向?qū)ο蟮娜筇匦裕悍庋b、繼承、多態(tài)
本節(jié)只介紹封裝,封裝是將數(shù)據(jù)和操作數(shù)據(jù)進(jìn)行有機(jī)結(jié)合,隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外公開接口來和對(duì)象進(jìn)行交互
封裝本質(zhì)上是一種管理,類似兵馬俑,如果什么都不管兵馬俑就會(huì)被隨意破壞那么我們首先建一座房子把兵馬俑給封裝起來。
但是我們不能全部封裝起來,所以開放了搜票通道,買了門票的可以進(jìn)去參觀。類也是一樣,我們使用類數(shù)據(jù)和方法都封裝一下。
不想給別人看的,我們使用proteced/private把成員封裝起來。開放一些共有的成員函數(shù)對(duì)成員合理的訪問。所以封裝本質(zhì)上是一種管理
Warning:在類中private域聲明的變量?jī)H僅是聲明,但是沒有開空間,我們只有在實(shí)例化的時(shí)候才算是定義,public域下亦是如此。
總結(jié)就是定義是開空間,在實(shí)例化后才是定義,class里只是聲明
三、類的實(shí)例化
用類類型創(chuàng)建對(duì)象的過程,稱為類的實(shí)例化
1.類限定了有哪些成員,定義出的一個(gè)類并沒有分實(shí)際的內(nèi)存空間來存儲(chǔ)它
2.一個(gè)類可以實(shí)例化多個(gè)對(duì)象,實(shí)例化出的對(duì)象占用實(shí)際的物理空間,存儲(chǔ)類成員變量
3.類實(shí)例化出對(duì)象就像現(xiàn)實(shí)中造車,類是車的設(shè)計(jì)圖,只負(fù)責(zé)設(shè)計(jì)需要什么東西,但并沒有實(shí)體,同樣類也只是個(gè)設(shè)計(jì),實(shí)例化出的對(duì)象才能實(shí)際存儲(chǔ)數(shù)據(jù),占用物理空間
上圖這個(gè)只算class里變量的大小,因此只保存成員變量,成員函數(shù)存放在公共的代碼段
那么定義一個(gè)空類呢?
class Cpp{}
那么sizeof的大小為1 , 而不是0,因?yàn)槿绻粋€(gè)類沒有成員,那么他的對(duì)象需要給1byte進(jìn)行占位
標(biāo)識(shí)對(duì)象存在,這1個(gè)byte不存儲(chǔ)有效數(shù)據(jù)
四、this指針
C++編譯器給每個(gè)非靜態(tài)成員函數(shù)增加了一個(gè)隱藏的指針參數(shù),讓該指針指向當(dāng)前對(duì)象(函數(shù)運(yùn)行時(shí)調(diào)用該函數(shù)的對(duì)象),在函數(shù)體中,所以成員變量的操作都是通過該指針去訪問
下面的代碼為編譯器處理成員函數(shù)的this指針,也可以不寫那么編譯器會(huì)自動(dòng)傳隱含的this指針
class Date{ public: void date(int year, int month, int day){ this->_year = year; this->_month = month; this->_day = day; } void Print(){ cout << _year << "/" << _month << "/" << _day <<endl; } private: int _year; int _month; int _day; };
this指針特性:
1.this指針的類型:類類型* const
2.只能在成員函數(shù)的內(nèi)部使用
3.this指針本質(zhì)上是一個(gè)成員函數(shù)的形參,是對(duì)象調(diào)用成員函數(shù)時(shí),將對(duì)象地址作為實(shí)參傳遞給this形參。所以對(duì)象中不存儲(chǔ)this指針
4.this指針是成員函數(shù)第一個(gè)隱含的指針形參,一般情況由編譯器通過ecx寄存器自動(dòng)傳第,不需要用戶傳遞
五、默認(rèn)成員函數(shù)
上圖為默認(rèn)的成員函數(shù),那么如果定義了一個(gè)class而里面什么都不寫的話,仍會(huì)自動(dòng)生成上面6個(gè)默認(rèn)成員函數(shù)
1. 構(gòu)造函數(shù)
我們首先要介紹的就是構(gòu)造函數(shù),因?yàn)橐话阍贑語言中一般會(huì)先進(jìn)行初始化,在C++中一般寫在類里,這樣我們?cè)趯?shí)例化的過程中就可以省去很多時(shí)間,而且避免了忘記初始化的風(fēng)險(xiǎn)。
構(gòu)造函數(shù)特征:
1.函數(shù)名與類名相同
2.無返回值
3.對(duì)象實(shí)例化時(shí)編譯器自動(dòng)調(diào)用對(duì)應(yīng)的構(gòu)造函數(shù)
4.構(gòu)造函數(shù)可以重載
所以構(gòu)造函數(shù)實(shí)際上能夠做到我們對(duì)象一定義出來就初始化了
class Date{ public: Date(){ _year = 0; _month = 0; _day = 0; } //帶參構(gòu)造函數(shù) Date(int year, int month, int day){ _year = year; _month = month; _day = day; } //全缺省,注意默認(rèn)構(gòu)造函數(shù)只能有一個(gè),所以只能選一種我們推薦用全缺省方式的構(gòu)造函數(shù) Date(int year=2022, int month = 2, int day = 20){ _year = year; _month = month; _day = day; } void date(int year, int month, int day){ this->_year = year; this->_month = month; this->_day = day; } void Print(){ cout << _year << "/" << _month << "/" << _day <<endl; } private: int _year; int _month; int _day; }; int main(){ Date day1; //注意這種是調(diào)用無參構(gòu)造函數(shù) Date day2(2021,10,19); //帶參構(gòu)造函數(shù) Date day3(); //函數(shù)聲明,返回一個(gè)日期類型的對(duì)象 }
Warning:
如果用戶顯示定義了構(gòu)造函數(shù),編譯器將不再生成內(nèi)置類型不會(huì)初始化 ,如int/char/double/指針等自定義類型會(huì)調(diào)用他的構(gòu)造函數(shù)初始化,如struct/class/union
2. 析構(gòu)函數(shù)
對(duì)象在銷毀時(shí)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),完成類的一些資源清理工作
析構(gòu)特征:
1.在類名的前面加上字符: ~
2.無參數(shù)無返回值
3.一個(gè)類有且只有一個(gè)析構(gòu)函數(shù)。如果沒有定義系統(tǒng)將自動(dòng)生成默認(rèn)的
4.對(duì)象生命周期結(jié)束時(shí),C++編譯系統(tǒng)自動(dòng)調(diào)用析構(gòu)函數(shù)
class SeqList { public : SeqList (int capacity = 10) { _pData = (DataType*)malloc(capacity * sizeof(DataType)); assert(_pData); _size = 0; _capacity = capacity; } ~SeqList() { if (_pData) { free(_pData ); // 釋放堆上的空間 _pData = NULL; // 將指針置為空 _capacity = 0; _size = 0; } } private : int* _pData ; size_t _size; size_t _capacity; };
3. 拷貝函數(shù)
顧名思義就是拷貝一個(gè)一摸一樣的對(duì)象
特征:
1.是構(gòu)造函數(shù)的一個(gè)重載形式
2.參數(shù)只有一個(gè)且必須使用引用傳參,使用傳值方式會(huì)引發(fā)無窮遞歸調(diào)用
下面就會(huì)引發(fā)無窮遞歸,解決辦法就是在Date類型后面加一個(gè)引用,這里就變成了用別名區(qū)分
3. 如果未定義,系統(tǒng)生成默認(rèn)的 拷貝構(gòu)造函數(shù)。默認(rèn)的拷貝構(gòu)造函數(shù)對(duì)象按內(nèi)存存儲(chǔ)按字節(jié)序完成拷貝,這種拷貝成為淺拷貝
4. 賦值運(yùn)算符重載
我們先了解一個(gè)概念叫運(yùn)算符重載,具有其返回值類型,函數(shù)名以及參數(shù)列表
關(guān)鍵字:operator后面接需要重載的運(yùn)算符符號(hào)
Warning:
1.作為類成員的重載函數(shù)時(shí),其形參看起來比操作數(shù)數(shù)目少一個(gè)成員函數(shù),實(shí)際上并不是這樣子的,操作符有一個(gè)默認(rèn)形參this,限定為第一個(gè)形參
2.以下符號(hào)不能重載:.* , :: . sizeof , ?: . .
3.我們定義operation一般在public里面而不是全局,因?yàn)槿绻覀冃薷牟涣藀rivate里面的成員變量,就保證不了封裝性
特征:
1. 參數(shù)類型
2.返回值
3.檢查是否自己給自己賦值
4. 返回*this
5. 一個(gè)類如果沒有顯示定義賦值運(yùn)算符重載,編譯器也會(huì)生成一個(gè),完成對(duì)象按字節(jié)序的值拷貝
下面就簡(jiǎn)單實(shí)現(xiàn)了日期增加N天的運(yùn)算符賦值
//Date day(2021,10,10); //day += 20; Date& Date::operator+=(int day){ if(day<0){ return *this -= -day; }else{ _day += day; //如果日期不合法,進(jìn)位 while(_day > GetMonthDay(_year, _month)){ _day -= GetMonthDay(_year, _month); ++_month; if(_month == 13){ ++_year; _month = 1; } } } return *this; }
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++ 虛函數(shù)和純虛函數(shù)的區(qū)別分析
這篇文章主要介紹了C++ 虛函數(shù)和純虛函數(shù)的區(qū)別,幫助大家更好的理解和學(xué)習(xí)c++的相關(guān)知識(shí),感興趣的朋友可以了解下2020-10-10linux c++ 服務(wù)器端開發(fā)面試必看書籍整理
這篇文章主要介紹了linux c++ 服務(wù)器端開發(fā)面試必看書籍整理,需要的朋友可以參考下2020-02-02C語言單鏈表實(shí)現(xiàn)圖書管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言單鏈表實(shí)現(xiàn)圖書管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03C++運(yùn)行時(shí)類型識(shí)別與轉(zhuǎn)換實(shí)現(xiàn)方法
運(yùn)行時(shí)類型識(shí)別可能被認(rèn)為是C++中一個(gè)”次要“的特征,當(dāng)程序員在編程過程中陷入非常困難的境地時(shí),實(shí)用主義將會(huì)幫助他走出困境2022-10-10