C++初階——類和對象(一)
一、面向過程和面向對象
1.面向過程
面向過程的程序設計(Procedure-Oriented Programming),簡稱POP,是一種是以程序執行流程為核心的編程范式。它是先分析出解決問題所需要的的步驟,然后用函數把這些步驟一步步地實現,在使用的時候依次調用就可以了。
2.面向對象
面向對象的程序設計(Object-Oriented Programming),簡稱OOP,關注的不再是完成一個任務的過程,而是完成這個任務涉及到的對象
。比如,在點外賣這一過程中,就涉及到用戶,商家和騎手這幾個對象。專業一點來講,面向對象編程(OOP)以現實世界實體映射為核心,將問題域抽象為對象的集合,每個對象包含數據
和方法(函數
)的封裝體。其哲學源于亞里士多德的“實體-屬性”論,通過類(Class)定義對象的藍圖(設計圖紙),實現“分類-實例化”的認知建模。
面向對象有三大特性:封裝、繼承、多態。
(1)封裝
- 將
數據
和操作數據的方法(函數
)進行有機結合,隱藏對象的屬性和實現細節,僅對外公開接口來和對象進行交互。 - C++實現封裝的方式:用類將對象的屬性與方法結合在一塊,讓對象更加完善,通過訪問權限選擇性的將其接口提供給外部的用戶使在
類(class)
中,通過訪問修飾符(private
/public
)控制數據暴露程度,提升隱私性和安全性。 - 2024年波音787航電系統升級時,因多個函數共享
navigation_state
全局變量,導致姿態控制模塊與通信模塊數據沖突,引發短暫系統宕機;防止外部誤操作:通過private
/public
修飾符,限制數據的直接訪問,可以讓銀行賬戶的balance(余額)
字段僅允許通過withdraw()
方法修改;防御性編程:2024年特斯拉自動駕駛系統升級后,傳感器數據的封裝層攔截了12%的非法訪問請求,避免了系統崩潰。 - 在C++初階的類和對象內容,我們主要就是圍繞封裝這一特性展開。
(2)繼承
- 繼承(Inheritance)是面向對象編程中實現代碼復用和層次抽象的核心機制,允許子類繼承父類的屬性和方法。這里不過多介紹,在C++進階的內容,我們會詳細講解。
(3)多態
- 多態(Polymorphism)是面向對象編程中同一接口在不同上下文中表現不同行為的能力,其核心在于“一個接口,多種實現”。這也是非常重要的內容,同樣,在C++進階中,我們會詳細講解。
二、類的介紹
類定義了一個新的作用域,類的所有成員都在類的作用域中。通過class關鍵字將數據
與操作(成員函數
)綁定。在類體外定義成員時,需要使用 ::
域作用限定符指明成員屬于哪個類域,比如在類里面聲明一個成員函數,在類外面定義時,就要使用 ::
。
我們先來簡單的感受一下:
class Stack
{
public:// 成員函數void Init(int defaultCapacity = 4)//提供一個缺省參數,如果沒有傳參,就使用這里的值{a = (int*)malloc(sizeof(int) * capacity); //基本操作,檢查動態內存開辟是否成功if (nullptr == a){perror("malloc fail");return;}capacity = defaultCapacity;top = -1;}void Push(int x){//...a[++top] = x;}void Destroy(){free(a);a = nullptr;top = capacity;}
private:// 成員變量int* a;int top;int capacity;
};
int main()
{return 0;
}
在這里,我們主要是熟悉一下類的使用,沒有詳細實現具體的內容,關于棧,在數據結構專欄中已經進行了詳細的講解。在一個類中,重要的是訪問限定符——public
、private
和protect,我們詳細介紹一下:
- public修飾的成員在類外可以直接被訪問
- protected和private修飾的成員在類外不能直接被訪問(此處protected和private是類似的)
- 訪問權限作用域從該訪問限定符出現的位置開始直到下一個訪問限定符出現時為止
- 如果后面沒有訪問限定符,作用域就到 } 即類結束。
- class的默認訪問權限為private,struct為public(因為struct要兼容C)
如圖所示:
struct(結構體)
在C語言中,里面是不可以定義函數的,但是在C++中,struct升級成了類,可以定義成員函數,但是struct里面的內容默認是公開的(public)
,外界可以隨意訪問,也是兼容了C語言結構體的性質,但class就不一樣了:
class默認是私有,需要加上public聲明才能被訪問,如圖:
允許外界訪問的是函數func,至于成員變量a、b,則是不想公開的。 - 在這里,我們也可以在類里面給出函數的聲明,在類的外面給出函數的定義:
這里需要指定函數Print是屬于A這個類域。
我們來看下面一段代碼:
這里的year=year含義就不清楚了,到底是形參自己賦值給自己還是將形參賦值給成員變量?因此我們應當這樣寫:
三、類的實例化
類定義僅僅是邏輯的藍圖,就像是一個房間的設計圖紙,并不能真正的住進去,因此,我們需要對類進行實例化才會創建出具體的對象,分配內存空間,簡而言之,用類創建對象的過程,稱為類的實例化。同一個類可以實例化出多個不同的對象,比如:在特斯拉工廠的Robot類實例化后,每個機器人擁有了獨立的關節狀態;銀行系統的Account類只有實例化后,才會綁定具體賬戶持有者。我們來舉個例子:
class Stack
{
public:// 成員函數void Init(int defaultCapacity = 4){a = (int*)malloc(sizeof(int) * defaultCapacity);if (nullptr == a){perror("malloc fail");return;}capacity = defaultCapacity;top = -1;}void Push(int x){a[++top] = x;}void Destroy(){free(a);a = nullptr;top = capacity;}
private:// 成員變量int* a;int top;int capacity;
};int main()
{Stack st1;st1.Init(20);st1.Init();st1.Push(1);st1.Push(2);st1.Push(3);st1.Push(4);st1.Destroy();return 0;
}
這里還是一個簡單的棧,首先,我們實例化了一個棧st1,現在st1不是一個圖紙,而是有具體內存空間的對象,我們可以對一個實例化出來的對象進行有實際意義的操作,比如初始化開空間(這里開的20,如果沒有提供開多少的參數,也沒關系,因為這里使用了缺省參數int defaultCapacity = 4
),元素入棧,棧的銷毀等等,如果不進行實例化,是沒有任何意義的,比如:
直接對著圖紙插入數據,顯然是沒有任何意義的。
那么,我們剛才定義函數不是用了::
嗎?
注意,這里是定義,其實還是在畫圖紙,并不是真正的使用。在類體外定義成員時,需要使用 ::
域作用限定符指明成員屬于哪個類域,比如在類里面聲明一個成員函數,在類外面定義時,就要使用 ::
。
還有一個問題,在鏈表中,我們特意強調了結構體是自定義類型
,struct的使用是要帶上它的名字的,比如鏈表的結構體指針struct ListNode*
就是一個典型的例子,在C++中還需要這樣嗎?
答案是:不需要!
因為C++已經將結構體struct升級成了類,這是語法規定:
struct Stack
{
public:// 成員函數void Init(int defaultCapacity = 4){a = (int*)malloc(sizeof(int) * defaultCapacity);if (nullptr == a){perror("malloc fail");return;}capacity = defaultCapacity;top = -1;}void Push(int x){a[++top] = x;}void Destroy(){free(a);a = nullptr;top = capacity;}
private:// 成員變量int* a;int top;int capacity;
};int main()
{Stack st1;st1.Init(5);st1.Init();st1.Push(1);st1.Push(2);st1.Push(3);st1.Push(4);st1.Destroy();return 0;
}
本期總結+下期預告
本期內容,我們正式進入C++初階的類和對象部分,這是C++中非常重要的內容,下期內容繼續為大家帶來相關的知識!
感謝大家的關注,我們下期再見!