一、基本概念
同一操作作用于不同的對象,產生不同的執行結果
👉 就像「按F1鍵」:在Word彈出幫助文檔,在PS彈出畫筆設置,?同一個按鍵觸發不同功能
(1)多態類型
類型 | 實現方式 | 綁定時機 |
---|---|---|
?靜態多態 | 函數重載、運算符重載 | 編譯時綁定 |
?動態多態 | 虛函數+繼承體系 | 運行時綁定 |
(2)動態多態三要素
多態滿足條件
- 有繼承關系
- 子類重寫父類中的虛函數
多態使用條件
- 父類指針或引用指向子類對象
重寫:函數返回值類型 函數名 參數列表 完全一致稱為重寫 (缺一不可)
class 父類名 {
public:virtual 返回類型 函數名(參數列表) {// 函數體}
};
(3)示例代碼
// 父類
class Animal {
public:virtual void speak() { // 1. 虛函數聲明cout << "動物發聲" << endl;}
};// 子類
class Cat : public Animal { // 1. 繼承關系
public:void speak() override { // 2. 重寫虛函數cout << "喵喵" << endl; }
};// 多態調用
void doSpeak(Animal& animal) { // 3. 父類引用接收子類對象animal.speak(); // 運行時決定調用哪個實現
}void doSpeak(Animal *animal) {// 4.用指針接收子類對象animal->speak();
}void test() {Cat cat;doSpeak(cat); // 輸出:喵喵
}
(4)重要特性
?函數重寫嚴格一致:(此處是函數內參數不一致)
// 錯誤示例:參數不同
class Animal { virtual void func(int) };
class Cat : public Animal { void func() }; // 不會觸發多態
二、多態原理
當子類重寫父類的虛函數,子類中的虛函數表內部,會替換成 子類的虛函數地址
例
class Animal
{
public://虛函數virtual void speak(){cout << "動物在說話" << endl;}
};
//貓類
class Cat : public Animal
{
public://重寫 函數返回值類型 函數名 參數列表 完全相同virtual void speak(){cout << "小貓在說話" << endl;}
};
原理概況
當父類的指針或者引用指向子類對象時候,發生多態
Animal & animal = cat;
animal.speak();
vfptr - 虛函數(表)指針v - virtual
f - function
ptr - pointervtable - 虛函數表v - virtual
f - function
table - table
三、純虛函數和抽象類
在多態中,通常父類中虛函數的實現是毫無意義的,主要都是調用子類重寫的內容
因此可以將虛函數改為純虛函數,當類中有了純虛函數,這個類也稱為抽象類
純虛函數語法:virtual 返回值類型 函數名(參數列表)= 0 ;
virtual void func() = 0;
抽象類特點:
1、無法實例化對象若Base是抽象類,則下面兩行報錯 Base b; new Base;
2、子類必須重寫抽象類中的純虛函數,否則也屬于抽象類
寫純虛函數意義就是想讓子類重寫一遍純虛函數
四、虛析構與純虛析構
1.核心問題
內存泄漏場景
class Animal {
public:~Animal() { // ? 普通析構cout << "Animal析構" << endl;}
};class Cat : public Animal {
public:~Cat() {cout << "Cat析構" << endl;delete[] m_data; // 堆內存資源}
private:int* m_data = new int[100];
};void test() {Animal* pet = new Cat();pet->speak();delete pet; // 僅調用Animal析構 → 內存泄漏!
}
執行結果:
Animal析構
(Cat析構未被調用 → m_data內存泄漏)
2.解決方案對比
方案類型 | 語法示例 | 類性質 | 實現要求 | 使用場景 |
---|---|---|---|---|
?虛析構 | virtual ~Animal() {} | 普通類 | 必須實現 | 需要實例化基類對象 |
?純虛析構 | virtual ~Animal() = 0; | 抽象類 | 必須單獨實現 | 強制子類實現特定行為 |
3.具體實現
1. 虛析構函數
class Animal {
public:virtual ~Animal() { // ? 虛析構聲明cout << "Animal虛析構" << endl;}
};// 正確執行結果:
// Cat析構
// Animal虛析構
2. 純虛析構函數
class Animal {
public:virtual ~Animal() = 0; // 純虛析構聲明
};// 必須單獨實現
Animal::~Animal() { // ? 純虛析構實現cout << "Animal純虛析構" << endl;
}
特性:
- 使類成為抽象類(無法實例化)
- 子類必須實現析構函數
class Cat : public Animal {
public:~Cat() override { // 必須實現cout << "Cat析構" << endl;}
};