C++中的類與對象深度解析
初始化列表
引論
//初始化列表的引出
class B
{
public:
B()
{
cout << "我是B的構造函數(shù)" << endl;
}
private:
int _b;
};
class A
{
public:
A()
{
cout << "我是A的構造函數(shù)" << endl;
}
private:
int _a;
B b;
};
int main()
{
A a;
return 0;
}

匯編驗證:

初始化列表
c++推薦使用初始化列表進行初始化
什么是初始化列表?
一個冒號開始,以逗號分隔的數(shù)據成員列表,每個成員變量后面放一個括號,括號中放初始值或者表達式
:_a(1)
,_aa(2)
這個就是初始化列表
//初始化列表使用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ù)體之前調用自定義類型的構造函數(shù),寫了初始化列表是會進入函數(shù)體(花括號)然后調用,具體的可以觀察匯編
- 成員變量只能在初始化列表里出現(xiàn)一次
- 成員變量包含引用和const變量時,必須在初始化列表里初始化
引用和const變量必須初始化
- 成員變量的聲明次序就是初始化順序,與在初始化列表里先后順序無關

初始化列表是推薦使用的,如果初始化列表不能解決問題,混著用(在構造函數(shù)體內初始化)就行了
explicit關鍵字
引論
//int賦給對象demo
class A
{
public:
A(int){}
};
int main()
{
A a = 1;
return 0;
}

這么寫是合法的,賦值的過程發(fā)生了隱式類型轉換,前提是必須有A(int這樣的構造函數(shù))
//多個int賦給對象demo
class A
{
public:
A(int,int){}
};
int main()
{
A a = {1,2};
return 0;
}

C++11支持多參數(shù)轉換,C++98不支持
explicit關鍵字使用
前面提到,int可以賦給對象是隱式類型轉換,如果要禁止這種用法,則用explicit修飾對應的構造函數(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)成員變量不是單單屬于某一個對象的,一個類創(chuàng)建的多個對象使用這個靜態(tài)成員變量時使用的也是同一塊內存,即所有對象共有該靜態(tài)成員變量
一份內存,多對象使用
靜態(tài)成員函數(shù)一般用來訪問靜態(tài)成員,沒有this指針
由于沒有this指針,所以無法訪問非靜態(tài)的成員
計算類的大小時不包括靜態(tài)成員

計算類的大小可以認為是計算對象的大小,因為每個對象共有靜態(tài)成員變量,所以不能認為該變量特定屬于某一個對象
調用靜態(tài)成員函數(shù),初始化靜態(tài)成員變量
//調用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;}//調用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)成員變量不能給缺省值,必須在類外初始化,因為在類外初始化時才分配空間,所以不在類外初始化就不能用,用了可能會導致鏈接錯誤
靜態(tài)成員函數(shù)不能調用非靜態(tài)成員函數(shù),非靜態(tài)成員函數(shù)可以調用靜態(tài)成員函數(shù)
普通靜態(tài)函數(shù)需要通過this指針調用,而靜態(tài)成員函數(shù)沒有this指針–百度
待了解:鏈接屬性
友元
引論

友元
什么是友元?
友元是一種定義在類外部的普通函數(shù)或類,但它需要在類體內進行說明,為了與該類的成員函數(shù)加以區(qū)別,在說明時前面加以關鍵字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;
}

隨筆記錄:編譯器找一些聲明只會往上找
類的聲明:class A;
如果我們在一個類內想訪問另一個類的私有成員,就需要友元類
class Time
{
public:
void GetData()
{
cout << d._year << d._month << d._day << endl;
}
private:
Date d;//借助這個對象
};
class Date
{
friend class Time;
private:
int _year;
int _month;
int _day;
};
int main()
{
return 0;
}

友元==突破類域
內部類
基礎概念
什么是內部類?
類里面定義一個類,這就叫內部類
內部類就是外部類的友元類,所以內部類可以訪問外部類的成員,用法也和友元類很像
計算類的大小時不算內部類
內部類內可以直接訪問外部類的靜態(tài)成員,不需要通過類名
內部類受到類域影響和訪問限定符限制
內部類的使用
//內部類使用demo
class A
{
public:
class B
{
public:
B(const A& a)
{
cout << "我是內部類B" << endl;
cout << "我可以訪問外部類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;
}

其實C++不咋用內部類,Java喜歡用內部類
補充
析構順序例題
類A、B、C、D,問下面程序中析構函數(shù)的調用順序?
C c;
int main()
{
A a;
B b;
static D d;
return 0;
}
答案:析構順序 B A D C
構造順序:C A B D
析構順序是D B C A嗎?不是
- 析構函數(shù)的調用時期:對象聲明周期結束后
- 靜態(tài)的變量存儲在全局區(qū),main函數(shù)結束后會銷毀棧幀
①因為a,b都是局部對象,先構造則后析構,構造時是AB,則析構肯定是BA
換個角度理解,棧的特點是先進后出,那a先入棧就應該后銷毀,所以b先調用析構函數(shù)
②剩下C D,C是全局對象,D是靜態(tài)局部對象,這兩個誰先析構?
靜態(tài)局部變量先析構,全局變量C再析構
D先析構,C后析構,即DC
全局對象和靜態(tài)局部對象的釋放優(yōu)先級在網上沒有找到很好的解釋
個人理解:CD都存在全局區(qū),所以CD的構造順序和析構順序應該是相反的,即構造是CD,則析構是DC
組合①②,得到BADC
這種題的技巧:把局部變量作為一組,把全局和靜態(tài)變量作為一組,寫出兩個相應的構造順序,再逆置一下就得到相應的析構順序,又因為局部變量先析構,再拼接兩組的析構順序得到答案
可以把上面那段代碼拷到編譯器上,然后自己寫代碼驗證答案
總結
- 初始化列表提供了一種更好的初始化的方式,如果初始化列表不能單獨完成任務,就結合構造函數(shù)體完成初始化任務
- explicit可以禁止內置類型和自定義類型的轉換,具體操作就是修飾對應的構造函數(shù)
- static成員可以牽扯出很多東西,比如靜態(tài)成員函數(shù)可不可以非靜態(tài)變量等等,抓住關鍵點:靜態(tài)成員函數(shù)沒有this指針,static成員變量始終是一塊內存,類外初始化才會分配空間
- 友元主要解決了我們在類外不能訪問私有成員變量的問題,本質上破壞了封裝,不建議大量使用
- 內部類,C++一般不怎么用,內部類理解為外部類的友元,同時受到訪問限定符的限制,類外使用內部類得用::突破類域限制
- 面向對象是在模擬是在抽象模擬我們的現(xiàn)實世界!
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!
相關文章
C++實現(xiàn)LeetCode(189.旋轉數(shù)組)
這篇文章主要介紹了C++實現(xiàn)LeetCode(189.旋轉數(shù)組),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下2021-07-07
QT利用QPdfWriter實現(xiàn)繪制PDF(支持表單輸出)
這篇文章主要為大家詳細介紹了QT如何利用QPdfWriter實現(xiàn)繪制PDF,并可以支持表單輸出。文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2023-01-01
C語言二叉樹常見操作詳解【前序,中序,后序,層次遍歷及非遞歸查找,統(tǒng)計個數(shù),比較,求深度】
這篇文章主要介紹了C語言二叉樹常見操作,結合實例形式詳細分析了基于C語言的二叉樹前序,中序,后序,層次遍歷及非遞歸查找,統(tǒng)計個數(shù),比較,求深度等相關操作技巧與注意事項,需要的朋友可以參考下2018-04-04

