歡迎來到干貨小倉庫,堪比沙漠!!!
從“Hello World”到改變世界,中間隔著千萬次'再試一次'.
1.多態的概念
例如:在買火車票時,若是普通人買票時,是全價買票;學生買票時,是半價買票;軍人買票時,是優先買票。
2.多態的定義及實現
2.1多態的構成條件
多態是在不同繼承關系的類對象,去調用同一函數,產生不同的行為。比如Student繼承了Person。Person對象買全價票,Student對象買半價票。
示例:
那么在繼承中要構成多態的條件有兩個條件:
1、必須通過基類的指針或引用調用虛函數。
2、被調用的函數必須是虛函數,且派生類必須對基類的虛函數進行重寫。
2.2虛函數
虛函數:即被virtual修飾的類成員函數稱為虛函數。
class Person {
public:virtual void BuyTicket() { cout << "買票-全價" << endl;}
};
2.3虛函數的重寫
條件
①是虛函數
②函數名、返回值和參數類型必須相同
但是有兩個例外:
1.協變(基類和派生類的虛函數返回值類型可以不同),但是要求返回值類型必須是父子關系的指針和引用。
2.派生類的重寫虛函數可以不加 virtual,基類的重寫虛函數必須加上。(建議都加上)
示例:返回值的不同
class A
{ };
class B:public A
{ };class Person
{
public:virtual const A& Buyticket(){cout << "買票全價" << endl;return A();}
};
class Student :public Person
{
public:virtual const B& Buyticket(){cout << "買票半價" << endl;return B();}
};
2.4重載、重寫(覆蓋)和重定義(隱藏)的對比
3.C++ 11 override 和 final 關鍵字
3.1 final
作用:
①修飾虛函數,使該虛函數不能被重寫。
②修飾類,使該類不能被繼承。
示例:
3.2 override
作用:幫助派生類檢查是否對虛函數完成重寫,沒有重寫會報錯。
4.抽象類
在虛函數的后面寫上 =0,則這個函數為 純虛函數。
包含純虛函數的類叫做 抽象類(接口類).
4.1虛函數的重寫(接口繼承)
示例:以下程序的輸出結果是什么?
class A{public:virtual void func(int val = 1){ std::cout<<"A->"<< val <<std::endl;}virtual void test(){ func();}};class B : public A{public:void func(int val=0){ std::cout<<"B->"<< val <<std::endl; }};int main(){B*p = new B;p->test();return 0;}
正確答案:B

4.2內聯函數、靜態成員函數和構造函數是否可以是虛函數?
5.多態的底層原理
5.1虛函數表
示例:以下 sizeof(Base) 是多少?
class Base
{
public:virtual void Func1(){cout << "Func1()" << endl;}
private:int _b = 1;
};
解析:通過編譯得到 sizeof(Base) 占 8個字節,多存了一個指針(指向虛函數表)。
注意:對基類的虛函數進行了重寫,其對應的虛函數表指針指向的地址也會發生變化。
1、基類b對象和派生類d對象虛表是不一樣的,這里我們發現Func1完成了重寫,所以d的虛表中存的是重寫的Derive::Func1,所以虛函數的重寫也叫作覆蓋,覆蓋就是指虛表中虛函數的覆蓋。重寫是語法的叫法,覆蓋是原理層的叫法。
示例:
2、虛函數表本質是一個存虛函數指針的指針數組,一般情況這個數組最后面放了一個nullptr。
3、總結一下派生類的虛表生成:
a.先將基類中的虛表內容拷貝一份到派生類虛表中。
b.如果派生類重寫了基類中某個虛函數,用派生類自己的虛函數覆蓋虛表中基類的虛函數。
c.派生類自己新增加的虛函數按其在派生類中的聲明次序增加到派生類虛表的最后。
示例:
4、派生類對基類的虛函數重寫了,故派生類產生的對象,共用一份虛表。
示例:
5.2虛函數表,存在哪里?
對比驗證法:根據多態的存儲模型,該對象的前面四個字節存放的是虛表的地址,分別與棧、靜態區、堆、常量區對比。
5.3動態綁定與靜態綁定
1. 靜態綁定又稱為前期綁定(早綁定),在程序編譯期間確定了程序的行為,也稱為靜態多態,比如:函數重載
2. 動態綁定又稱后期綁定(晚綁定),是在程序運行期間,根據具體拿到的類型確定程序的具體行為,調用具體的函數,也稱為動態多態。
6.多繼承的多態
6.1多繼承的虛函數表
觀察下圖可以看出:多繼承派生類的為重寫的虛函數放在第一個繼承基類部分的虛函數表中
為什么重寫func1(),Base1 和 Base2 的虛表中的地址不一樣,但結果一樣?
需要從底層的匯編進行深入刨析,根據其會變得調用,分析得到 編譯器做了處理,目的是為了修改 this 指針。
6.2菱形虛擬繼承的多態
覺得不錯的可以點贊+收藏咯!!!