類與對象(上)
- 一、面向過程和面向對象的區別
- 二、類
- 1、類的引入
- 2、類的定義
- (1)類的基本定義
- (2)類的成員函數的定義方法
- 3、類的訪問限定符
- 4、封裝
- 5、駝峰法命名規則
- 6、類的作用域
- 7、類的實例化
- (1)實例化的概念與作用
- (2)類沒有實例化對象
- (3)類有實例化對象
- 8、生命周期與作用域的關系
- 三、類對象模型
- 1、類對象的存儲方式(只保存成員變量,成員函數存放在公共的代碼區中)
- 2、C語言結構體內存對齊規則
- 3、計算類對象的大小
- 四、this指針
- 1、示例代碼
- 2、this指針的作用
- 3、成員函數的實際參數與錯誤
- 4、this指針的特性
一、面向過程和面向對象的區別
在學習C++之前,我們已經學了C語言,而C語言是面向過程的計算機語言,關注的是過程,即要求編程者分析出求解問題的步驟,進而通過函數調用的方式逐步解決問題;而C++是基于面向對象的計算機語言,關注的是對象,即將一件事情拆分成不同的對象,靠對象之間的交互完成要求。但是,因為C++是在C語言的基礎之上創建出來的計算機語言,所以C++是兼容C語言的,即C++不是純面向對象的語言,它可以面向對象和面向過程混編。
二、類
1、類的引入
在C語言中,有結構體struct的概念,在C++中,因為它兼容C語言的緣故,所以struct在C++中可以是結構體,但確切的說它升級成為了類,而類與結構體最明顯的兩個區別就是能在類里面定義函數和有訪問權限的概念。比如用C語言實現棧(參見棧與隊列),里面的結構體中只能有成員變量而不能有成員函數,所以,實現棧的一系列函數只能在結構體外去實現。但是,在C++中使用類時更喜歡用class而不是struct,雖然兩者在C++中都是類,但class的默認訪問權限為private,而struct的默認訪問權限為public。
2、類的定義
(1)類的基本定義
class className
{//類體:由成員函數和成員變量組成
}; //記得加上分號
- class為定義類的關鍵字,ClassName為要定義的類的名字,{}中的內容為類的主體,在類定義結束時,}后面的分號不能省略。
- 類體中的內容稱為類的成員:類中的變量稱為類的屬性或成員變量;類中的函數稱為類的方法或者成員函數。
(2)類的成員函數的定義方法
- 聲明和定義全部放在類體中,編譯器可能會將其當成內聯函數處理。
class Person
{
public:void ShowInfo(){cout << _name << " " << _sex << " " << _age << endl;}
private:char* _name;char* _sex;int _age;
};
- 類的成員函數的聲明放在.h文件中,成員函數的定義放在.cpp文件中,此時在成員函數的定義中,成員函數名前需要加類名::。
- 如果類的成員函數比較小,能夠成為inline函數,則可以直接在類里面定義,而如果是大函數、遞歸的成員函數,則應該用聲明和定義分離的方法定義成員函數。這樣代碼比較簡潔,可讀性比較高,閱讀用這種方法所寫的代碼時能夠比較容易地了解類的作用。
- 什么樣的函數適合inline函數參見萬字講解C++基礎
3、類的訪問限定符
- public修飾的成員在類外可以直接被訪問。
- protected和private修飾的成員在類外不能直接被訪問,即只能在類里面訪問,而在此處protected和private的作用是相似的。
- 訪問限定符的訪問權限作用域從該訪問限定符出現的位置開始,到下一個訪問限定符出現時結束或者后面沒有訪問限定符了,則到 }結束。
- 訪問限定符只在編譯時有用,當數據映射到內存后,被訪問限定符修飾的所有成員沒有任何區別。
4、封裝
將數據和操作數據的方法(類的成員函數)進行有機結合,隱藏對象的屬性和實現細節,僅對外公開接口和對象進行交互。
5、駝峰法命名規則
- 函數名、類名等所有單詞首字母大寫,如SnowDragon
- 變量首字母小寫,后面單詞首字母大寫,如snowDragon
- 成員變量,首單詞前面加_,如_snowDragon
6、類的作用域
類似于函數、循環等等,它們都具有作用域,類也具有作用域,即類的{}所括起來的區域。類的所有成員都被包含在這個作用域中。當在類的類體外定義成員時,需要使用::作用域操作符指明定義的成員屬于哪個類域。
7、類的實例化
(1)實例化的概念與作用
- 用類類型創建對象的過程,稱為類的實例化。
- 類是對對象進行描述的,即它是一個像模型一樣的東西,限定了類具有的成員,定義完成一個類時,編譯器并沒有分配實際的內存空間出來,即此時的類不能存儲數據。
- 一個類可以實例化出多個對象,而實例化出的對象是具有實際的物理空間的,即它們能夠存儲類的成員變量的數據。
(2)類沒有實例化對象
(3)類有實例化對象
- 因為類是定義在全局作用域中的,而main函數是在類外,所以此處要在main函數中調用類的成員變量時,得將類中類的成員變量用public訪問限定符修飾,否則無法進行訪問。
- 對_name和_sex成員變量賦值時,由于上圖的代碼在main函數中是用常量字符串對其進行賦值,所以_name和_sex需用const進行修飾。
8、生命周期與作用域的關系
- 作用域影響變量的訪問,但不影響變量的生命周期。
- 生命周期與變量存儲的位置有關,當變量所在的空間是在棧上的,當變量所在的作用域結束時,該作用域在棧上的空間將被操作系統回收,而變量也在這塊被回收的空間中,即它的生命周期也結束了。
三、類對象模型
1、類對象的存儲方式(只保存成員變量,成員函數存放在公共的代碼區中)
- 如果要調用類的成員函數,編譯器會在編譯鏈接時根據函數名去公共代碼區找到被調用的函數的地址,用反匯編的方式查看時,會有call該函數的地址的代碼。
2、C語言結構體內存對齊規則
- 第一個成員從在與結構體偏移量為0的地址處開始存儲。
- 對齊數為在編譯器默認的對齊數與該成員類型的大小中的較小值(VS編譯器中的默認對齊數為8)。
- 其他成員變量要對齊到對齊數的整數倍的地址處才可以開始存儲。
- 結構體總大小為:最大對齊數(所有變量對齊數的最大值與默認對齊數,兩者中最小的那個)的整數倍。
- 如果嵌套了結構體,嵌套的結構體對齊到自己的最大對齊數的整數倍處,而結構體的整體大小就是所有最大對齊數(含嵌套結構體的對齊數)的整數倍。
3、計算類對象的大小
- 一個類的大小就是該類中所有成員變量的大小之和,計算大小總和的方法要注意內存對齊規則。
- 如果類為空類,編譯器會給該類一個字節來唯一標識這個類的對象。
四、this指針
1、示例代碼
class Date
{
public:void Init(int year, int month, int day){//this = nullptr;_year = year;_month = month;_day = day;}void Print(){cout << _year << " " << _month << " " << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;d1.Init(2023, 8, 15);d1.Print();Date d2;d2.Init(2023, 8, 16);d2.Print();return 0;
}
2、this指針的作用
- 在上方的示例代碼Date類中,有Init與Print兩個成員函數,但在兩個函數的函數體中沒有關于不同對象的區分,那當d1調用Init函數時,該函數是通過this指針進行訪問并設置對象。
- 即C++編譯器給每個”非靜態的成員函數“增加了一個隱藏的指針作為函數的形式參數,讓該指針指向當前對象(函數運行時調用該函數的對象),在函數體中對所有“成員變量”的操作都是通過這個指針去訪問的。只不過所有的操作對用戶都是透明的,即用戶不需要自己傳遞當前對象的地址作為參數,編譯器會自動完成這些操作。
3、成員函數的實際參數與錯誤
4、this指針的特性
- this指針的類型:類類型* const,因為this被const修飾了,所以在成員函數中,不能給this指針賦值(上方代碼中注釋掉的那行代碼)且只能在“成員函數”的內部使用。
- this指針本質上是“成員函數”的形參,當對象調用成員函數時,編譯器會將對象的地址作為實參傳遞給this形參,因為this是形參,所以它存在棧上。
- this指針是類的成員函數的形式參數中第一個隱含的指針形參,在VS編譯器下,傳給this的實參是通過ecx寄存器自動傳遞的,不需要用戶自己填寫該實參。而用寄存器傳遞會提高this訪問變量的效率,是否對this指針進行優化是由編譯器決定的。
- 只要類的成員函數內部不需要this進行訪問,則該成員函數的this指針可以為空,即調用這個成員函數的對象可以為nullptr。
- 實參和形參位置不能顯示傳遞和接收this指針,但是可以在成員函數內部使用this指針。
本文到這里就結束了,如有錯誤或者不清楚的地方歡迎評論或者私信
創作不易,如果覺得博主寫得不錯,請務必點贊、收藏加關注💕💕💕