目錄
- 引言
- 1.面向過程和面向對象初步認識
- 2.類的引入
- 3.類的定義
- 3.1聲明與定義全部放在類體中
- 3.2聲明與定義分離
- 4.類的訪問限定符及封裝
- 4.1訪問限定符
- 4.2封裝
- 5.類的作用域
- 6.類的實例化
- 類是對對象進行描述
- 一個類(一個類型變量)可以實例化出多個對象
- 7.類對象模型
- 7.1類對象的大小
- 7.2類對象的存儲方式
- 7.3結構體內存對齊規則
- 8.`this` 指針
- 8.1 this指針的引出
- 8.2 this指針的特性
- 總結:
引言
在面向對象編程(OOP)中,類(Class)和**對象(Object)**是兩個核心概念。
簡單來說,**類定義了對象的模板,而對象是根據類創建的具體實體**
。例如,假設有一個類叫做Car,描述了汽車的屬性(如顏色、品牌、型號)和行為(如加速、減速、轉向)。那么根據這個類,我們可以創建多個具體的汽車對象,每個對象都有自己的屬性和行為,但都基于相同的類模板。
在面向對象編程中,程序主要由對象組成,每個對象都是一個實例,具有特定的屬性(成員變量)和行為(成員函數)。類則用來定義對象的模板,描述了一類對象共同的屬性和行為。
1.面向過程和面向對象初步認識
面向對象編程(OOP)是一種以對象為中心的編程范式,它將數據和操作數據的方法封裝在對象中,使得對象可以通過方法與其他對象進行交互。在面向對象編程中,程序的設計和實現是圍繞著對象的概念展開的,強調對象之間的交互和繼承關系,以及多態性的特性。
面向過程編程(POP)是一種以過程為中心的編程范式,它將問題分解為一系列的步驟或過程,然后按照順序執行這些步驟來解決問題。在面向過程編程中,數據和操作數據的方法是分開的,程序的設計和實現是圍繞著函數或過程的概念展開的,強調按照步驟執行任務。
C語言是面向過程的,關注的是過程,分析求解問題
而C++是基于面向對象的,關注的是對象,將一件事情拆分成不同的對象,靠對象之間的交互完成
2.類的引入
相較于C語言,結構體中只能定義變量,而在C++中,結構體內不僅可以定義變量,還可以定義函數并在內部嵌套調用
如,C語言棧的實現
#include<iostream>using namespace std;
typedef int DataType;
struct Stack
{//初始化函數void Init(size_t capacity=5){_array = (int*)malloc(sizeof(int) * capacity);_capacity = capacity;_size = 0;}void Push(const DataType& data){_array[_size] = data;_size++;}DataType Top(){return _array[_size - 1];}void Destory(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}//成員變量DataType* _array;size_t _capacity;size_t _size;
};int main()
{Stack s;s.Init();s.Push(1);s.Push(3);s.Push(2);cout << s.Top() << endl;s.Destory();return 0;
}
而在C++中,結構體的定義,更習慣用 class
關鍵字來替代
3.類的定義
class name
{//成員函數//成員變量};
class 為定義類的關鍵字,name為類的名字
類的定義方式有倆種
3.1聲明與定義全部放在類體中
若成員函數在類中定義,那么編譯器可能會當作 內聯函數來處理
3.2聲明與定義分離
類聲明放
4.類的訪問限定符及封裝
4.1訪問限定符
C++實現封裝的方式:類與對象的屬性與方法結合在一起,設置訪問權限的選擇性將其接口提供外部使用
- public修飾的成員在類外可以直接被訪問
- protected和private修飾的成員在類外不能直接被訪問(此處protected和private是類似的)
- 訪問權限作用域從該訪問限定符出現的位置開始直到下一個訪問限定符出現時為止
- 如果后面沒有訪問限定符,作用域就到 } 即類結束。
- class的默認訪問權限為private,struct為public(因為struct要兼容C)
4.2封裝
在面向對象的三大特性中(封裝、繼承、多態),主要研究類的封裝特性,在類和對象階段
封裝:將數據和操作數據的方法進行有機結合,隱藏對象的屬性和實現細節,僅對外公開接口來
和對象進行交互。
封裝本質上是一種管理,讓用戶更方便使用類。
5.類的作用域
在C中,結構體的定義等價于一個變量的定義,而在C++中類的定義形成了一個新的作用域
C中有全局和局部,static靜態
而C++中則形成了一個新的作用域,就好比之前,一塊土地有公工區域(公共管理),和非公共區域(無人管理),然后類的定義,開始出現,私人住宅(別人允許你訪問,那么便可以做客參觀)
在類體外定義成員時,需要標識符 ::作用域操作符指明
void name::fun()
{//…………
}
6.類的實例化
用類類型創建對象的過程,稱為類的實例化
類是對對象進行描述
定義一個類,并沒有分配實際的內存空間來存儲它
注:類當中的成員函數也沒有空間? 類成員函數在定義后,就有了固定的存放位置,當創建類的實例化,并不會重復開辟成員函數的空間
一個類(一個類型變量)可以實例化出多個對象
多個類,分別占用實際的物理空間,儲存類成員變量
類比,實例化出對象就像在現實中使用建筑設計圖建造出房子,類就是設計圖,房子就是實例化
7.類對象模型
7.1類對象的大小
類對象的大小取決于其成員變量和成員函數
1.成員變量的大小:類中的每個成員變量都占用內存空間。基本數據類型(如int、float等)通常占用固定大小的內存空間,而對象、指針或其他用戶自定義類型的大小取決于其內部包含的成員變量。
2.對齊規則:在內存中,數據通常按照特定的對齊規則存儲,以提高訪問速度。對齊規則可以導致成員變量之間存在一些額外的空隙,以保證每個成員變量從正確的內存地址開始。對齊規則通常由編譯器和目標平臺決定。
3.繼承和虛函數:如果類繼承自其他類,或者包含虛函數,那么額外的內存空間可能會用于存儲指向虛函數表的指針(對于包含虛函數的類)或基類的成員變量(對于派生類)。
如:
//前面所創建的Stack的類與Stack1比較
class Stack1
{int x;int y;int z;
};int main()
{cout << sizeof(Stack) << endl<<sizeof(Stack1)<<endl;
}
7.2類對象的存儲方式
類對象包含類的各個成員
每個對象中成員變量是不同的,但是調用同一份函數,如果按照此種方式存儲,當一個類創建多個對象時,每個對象中都會保存一份代碼,相同代碼保存多次,浪費空間。
代碼只保存一份,在對象中保存成員函數的地址
只保存成員變量,成員函數存放在公共的代碼段
結論:一個類的大小,實際就是該類中”成員變量”之和,當然要注意內存對齊
注意空類的大小,空類比較特殊,編譯器給了空類一個字節來唯一標識這個類的對象
7.3結構體內存對齊規則
對齊規則和C語言中的結構體對齊規則是一樣
- 第一個成員在與結構體偏移量為0的地址處。
- 其他成員變量要對齊到某個數字(對齊數)的整數倍的地址處。 注意:對齊數 = 編譯器默認的一個對齊數 與 該成員大小的較小值。 VS中默認的對齊數為8
- 結構體總大小為:最大對齊數(所有變量類型最大者與默認對齊參數取最小)的整數倍。
- 如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數的整數倍處,結構體的整 體大小就是所有最大對齊數(含嵌套結構體的對齊數)的整數倍。
8.this
指針
8.1 this指針的引出
問題:當倆個同類型的類實例化,調用同一個成員函數,編譯器是怎么分辨出,是哪一個面向對象調用函數?
如:
//引用之前所定義的Stack 的類
int main()
{Stack d1;Stack d2;d1.Init();d2.Init();//~~~~return 0;
}
這里調用Init初始化,怎么分辨出是d1,還是d2調用?
這就是this指針的作用了> 在C++中,this指針是一個特殊的指針,它指向當前對象的地址。它是每個非靜態成員函數的隱式參數。當你在一個**成員函數內部引用類的成員變量或者調用其他成員函數**時,編譯器會自動地插入this指針。
實現的底層邏輯:
C++編譯器給每個“非靜態的成員函數“增加了一個隱藏的指針參數,讓該指針指向當前對象(函數運行時調用該函數的對象),在函數體中所有“成員變量”的操作,都是通過該指針去訪問。只不過所有的操作對用戶是透明的,即用戶不需要來傳遞,編譯器自動完成。
8.2 this指針的特性
- this指針的類型:類類型* const,即成員函數中,不能給this指針賦值。
- 只能在“成員函數”的內部使用
- this指針本質上是“成員函數”的形參,當對象調用成員函數時,將對象地址作為實參傳遞給
this形參。所以對象中不存儲this指針。 - this指針是“成員函數”第一個隱含的指針形參,一般情況由編譯器通過ecx寄存器自動傳
遞,不需要用戶傳遞
總結:
C++中通過類可以將數據 以及 操作數據的方法進行完美結合,通過訪問權限可以控制那些方法在類外可以被調用,即封裝,在使用時就像使用自己的成員一樣,更符合人類對一件事物的認知。