C++中的類與對(duì)象深度解析
初始化列表
引論
//初始化列表的引出 class B { public: B() { cout << "我是B的構(gòu)造函數(shù)" << endl; } private: int _b; }; class A { public: A() { cout << "我是A的構(gòu)造函數(shù)" << endl; } private: int _a; B b; }; int main() { A a; return 0; }
匯編驗(yàn)證:
初始化列表
c++推薦使用初始化列表進(jìn)行初始化
什么是初始化列表?
一個(gè)冒號(hào)開始,以逗號(hào)分隔的數(shù)據(jù)成員列表,每個(gè)成員變量后面放一個(gè)括號(hào),括號(hào)中放初始值或者表達(dá)式
:_a(1)
,_aa(2)
這個(gè)就是初始化列表
//初始化列表使用demo class A { public: A() :_a(1)//初始化列表 , _aa(2) { cout << _a << " " << _aa << endl; } private: int _a; int _aa; }; int main() { A a; return 0; }
- 存在自定義類型時(shí),初始化列表,不寫也認(rèn)為有
只是認(rèn)為啊,不寫初始化列表會(huì)在函數(shù)體之前調(diào)用自定義類型的構(gòu)造函數(shù),寫了初始化列表是會(huì)進(jìn)入函數(shù)體(花括號(hào))然后調(diào)用,具體的可以觀察匯編
- 成員變量只能在初始化列表里出現(xiàn)一次
- 成員變量包含引用和const變量時(shí),必須在初始化列表里初始化
引用和const變量必須初始化
- 成員變量的聲明次序就是初始化順序,與在初始化列表里先后順序無(wú)關(guān)
初始化列表是推薦使用的,如果初始化列表不能解決問(wèn)題,混著用(在構(gòu)造函數(shù)體內(nèi)初始化)就行了
explicit關(guān)鍵字
引論
//int賦給對(duì)象demo class A { public: A(int){} }; int main() { A a = 1; return 0; }
這么寫是合法的,賦值的過(guò)程發(fā)生了隱式類型轉(zhuǎn)換,前提是必須有A(int這樣的構(gòu)造函數(shù))
//多個(gè)int賦給對(duì)象demo class A { public: A(int,int){} }; int main() { A a = {1,2}; return 0; }
C++11支持多參數(shù)轉(zhuǎn)換,C++98不支持
explicit關(guān)鍵字使用
前面提到,int可以賦給對(duì)象是隱式類型轉(zhuǎn)換,如果要禁止這種用法,則用explicit修飾對(duì)應(yīng)的構(gòu)造函數(shù)
//explicit使用demo class A { public: explicit A(int){} }; int main() { A a = 1;//error return 0; }
static成員
靜態(tài)成員變量:static修飾的成員變量
靜態(tài)成員函數(shù):static修飾的成員函數(shù)
靜態(tài)成員變量不是單單屬于某一個(gè)對(duì)象的,一個(gè)類創(chuàng)建的多個(gè)對(duì)象使用這個(gè)靜態(tài)成員變量時(shí)使用的也是同一塊內(nèi)存,即所有對(duì)象共有該靜態(tài)成員變量
一份內(nèi)存,多對(duì)象使用
靜態(tài)成員函數(shù)一般用來(lái)訪問(wèn)靜態(tài)成員,沒有this指針
由于沒有this指針,所以無(wú)法訪問(wèn)非靜態(tài)的成員
計(jì)算類的大小時(shí)不包括靜態(tài)成員
計(jì)算類的大小可以認(rèn)為是計(jì)算對(duì)象的大小,因?yàn)槊總€(gè)對(duì)象共有靜態(tài)成員變量,所以不能認(rèn)為該變量特定屬于某一個(gè)對(duì)象
調(diào)用靜態(tài)成員函數(shù),初始化靜態(tài)成員變量
//調(diào)用static函數(shù)和初始化static變量的democlass A{public:static int Print(){cout << "static int Print()" << endl;return _aa;}private:int _a;static int _aa;};int A::_aa = 1;int main(){A::Print();return 0;}//調(diào)用static函數(shù)和初始化static變量的demo class A { public: static int Print() { cout << "static int Print()" << endl; return _aa; } private: int _a; static int _aa; }; int A::_aa = 1; int main() { A::Print(); return 0; }
靜態(tài)成員變量不能給缺省值,必須在類外初始化,因?yàn)樵陬愅獬跏蓟瘯r(shí)才分配空間,所以不在類外初始化就不能用,用了可能會(huì)導(dǎo)致鏈接錯(cuò)誤
靜態(tài)成員函數(shù)不能調(diào)用非靜態(tài)成員函數(shù),非靜態(tài)成員函數(shù)可以調(diào)用靜態(tài)成員函數(shù)
普通靜態(tài)函數(shù)需要通過(guò)this指針調(diào)用,而靜態(tài)成員函數(shù)沒有this指針–百度
待了解:鏈接屬性
友元
引論
友元
什么是友元?
友元是一種定義在類外部的普通函數(shù)或類,但它需要在類體內(nèi)進(jìn)行說(shuō)明,為了與該類的成員函數(shù)加以區(qū)別,在說(shuō)明時(shí)前面加以關(guān)鍵字friend。–百度百科
友元的作用
突破封裝
class Date { friend bool operator==(Date d1, Date d2); private: int _year; int _month; int _day; }; bool operator==(Date d1,Date d2) { return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day; } int main() { return 0; }
隨筆記錄:編譯器找一些聲明只會(huì)往上找
類的聲明:class A;
如果我們?cè)谝粋€(gè)類內(nèi)想訪問(wèn)另一個(gè)類的私有成員,就需要友元類
class Time { public: void GetData() { cout << d._year << d._month << d._day << endl; } private: Date d;//借助這個(gè)對(duì)象 }; class Date { friend class Time; private: int _year; int _month; int _day; }; int main() { return 0; }
友元==突破類域
內(nèi)部類
基礎(chǔ)概念
什么是內(nèi)部類?
類里面定義一個(gè)類,這就叫內(nèi)部類
內(nèi)部類就是外部類的友元類,所以內(nèi)部類可以訪問(wèn)外部類的成員,用法也和友元類很像
計(jì)算類的大小時(shí)不算內(nèi)部類
內(nèi)部類內(nèi)可以直接訪問(wèn)外部類的靜態(tài)成員,不需要通過(guò)類名
內(nèi)部類受到類域影響和訪問(wèn)限定符限制
內(nèi)部類的使用
//內(nèi)部類使用demo class A { public: class B { public: B(const A& a) { cout << "我是內(nèi)部類B" << endl; cout << "我可以訪問(wèn)外部類A的變量_a:" <<a._a << endl; } private: int _b; }; A(){} A(const B& b) { cout << b._b << endl;//error } private: int _a=1; }; int main() { A a; A::B b(a); return 0; }
其實(shí)C++不咋用內(nèi)部類,Java喜歡用內(nèi)部類
補(bǔ)充
析構(gòu)順序例題
類A、B、C、D,問(wèn)下面程序中析構(gòu)函數(shù)的調(diào)用順序?
C c; int main() { A a; B b; static D d; return 0; }
答案:析構(gòu)順序 B A D C
構(gòu)造順序:C A B D
析構(gòu)順序是D B C A嗎?不是
- 析構(gòu)函數(shù)的調(diào)用時(shí)期:對(duì)象聲明周期結(jié)束后
- 靜態(tài)的變量存儲(chǔ)在全局區(qū),main函數(shù)結(jié)束后會(huì)銷毀棧幀
①因?yàn)閍,b都是局部對(duì)象,先構(gòu)造則后析構(gòu),構(gòu)造時(shí)是AB,則析構(gòu)肯定是BA
換個(gè)角度理解,棧的特點(diǎn)是先進(jìn)后出,那a先入棧就應(yīng)該后銷毀,所以b先調(diào)用析構(gòu)函數(shù)
②剩下C D,C是全局對(duì)象,D是靜態(tài)局部對(duì)象,這兩個(gè)誰(shuí)先析構(gòu)?
靜態(tài)局部變量先析構(gòu),全局變量C再析構(gòu)
D先析構(gòu),C后析構(gòu),即DC
全局對(duì)象和靜態(tài)局部對(duì)象的釋放優(yōu)先級(jí)在網(wǎng)上沒有找到很好的解釋
個(gè)人理解:CD都存在全局區(qū),所以CD的構(gòu)造順序和析構(gòu)順序應(yīng)該是相反的,即構(gòu)造是CD,則析構(gòu)是DC
組合①②,得到BADC
這種題的技巧:把局部變量作為一組,把全局和靜態(tài)變量作為一組,寫出兩個(gè)相應(yīng)的構(gòu)造順序,再逆置一下就得到相應(yīng)的析構(gòu)順序,又因?yàn)榫植孔兞肯任鰳?gòu),再拼接兩組的析構(gòu)順序得到答案
可以把上面那段代碼拷到編譯器上,然后自己寫代碼驗(yàn)證答案
總結(jié)
- 初始化列表提供了一種更好的初始化的方式,如果初始化列表不能單獨(dú)完成任務(wù),就結(jié)合構(gòu)造函數(shù)體完成初始化任務(wù)
- explicit可以禁止內(nèi)置類型和自定義類型的轉(zhuǎn)換,具體操作就是修飾對(duì)應(yīng)的構(gòu)造函數(shù)
- static成員可以牽扯出很多東西,比如靜態(tài)成員函數(shù)可不可以非靜態(tài)變量等等,抓住關(guān)鍵點(diǎn):靜態(tài)成員函數(shù)沒有this指針,static成員變量始終是一塊內(nèi)存,類外初始化才會(huì)分配空間
- 友元主要解決了我們?cè)陬愅獠荒茉L問(wèn)私有成員變量的問(wèn)題,本質(zhì)上破壞了封裝,不建議大量使用
- 內(nèi)部類,C++一般不怎么用,內(nèi)部類理解為外部類的友元,同時(shí)受到訪問(wèn)限定符的限制,類外使用內(nèi)部類得用::突破類域限制
- 面向?qū)ο笫窃谀M是在抽象模擬我們的現(xiàn)實(shí)世界!
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++詳細(xì)講解內(nèi)存管理工具primitives
文章向大家介紹C++內(nèi)存管理primitives,主要包括primitives使用實(shí)例、應(yīng)用技巧、基本知識(shí)點(diǎn)總結(jié)和需要注意事項(xiàng),具有一定的參考價(jià)值,需要的朋友可以參考一下2022-06-06C語(yǔ)言新手練習(xí)題之求第n個(gè)斐波那契數(shù)
斐波那契數(shù)列這一個(gè)大一上C語(yǔ)言就有的問(wèn)題大家應(yīng)該都不陌生,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言新手練習(xí)題之求第n個(gè)斐波那契數(shù)的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11C語(yǔ)言利用UDP實(shí)現(xiàn)群聊聊天室的示例代碼
UDP是一個(gè)輕量級(jí)、不可靠、面向數(shù)據(jù)報(bào)的、無(wú)連接的傳輸層協(xié)議,多用于可靠性要求不嚴(yán)格,不是非常重要的傳輸,如直播、視頻會(huì)議等等。本文將利用UDP實(shí)現(xiàn)簡(jiǎn)單的群聊聊天室,感興趣的可以了解一下2022-08-08