關于虛函數實現多態(tài)的原理及分析
更新時間:2023年02月05日 16:37:38 作者:Cynantrs
這篇文章主要介紹了C++中如何實現多態(tài)問題,具有很好的參考價值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
1、C++中如何實現多態(tài)
- 基類中先聲明一個虛函數
- 至少有一個繼承該基類的子類
2、虛函數實現多態(tài)的原理
- 當一個類中出現虛函數或著子類繼承了虛函數時,就會在該類中產生一個虛函數表(virtual table),虛函數表實際上是一個函數指針數組(在有的編譯器作用下是鏈表),里面的每一個元素對應指向該類中的某一個虛函數的指針。
- 被該類聲明的對象會包含一個虛函數表指針(virtual table pointer),指向該類的虛函數表的地址。
- 虛函數的調用過程: 當一個對象要調用到虛函數時,先將對象內存中的vptr指針(虛函數表指針)指向定義該類的vtbl(虛函數表),vtbl再尋找里面的指針指向想要調用的虛函數,從而完成虛函數的調用。

2.1 單類繼承
定義一個父類
class Person{
public:
virtual void f(){cout << "use f()" << endl;}
virtual void g(){cout << "use g()" << endl;}
virtual void h(){cout << "use h()" << endl;}
};
父類對象其在內存中布局如下:

- 再定義一個子類,此時并不覆蓋父類的虛函數:
class Bag:public Person{
public:
virtual void i(){cout << "use i()" << endl;}
virtual void j(){cout << "use j()" << endl;}
};

可以看出虛函數表內的虛函數是按聲明順序進行排序的
父類虛函數排在子類虛函數之前
- 當我們把子類中的虛函數覆蓋掉:(修改Bag類)
class Bag:public Person{
public:
void f(){cout << "class Bag use fun" << endl;}
virtual void i(){cout << "use i()" << endl;}
virtual void j(){cout << "use j()" << endl;}
};

子類覆蓋的虛函數,放在父類原先放該虛函數的位置上。
所以當父類指針指向該子類對象時,會調用該子類的重載函數
2.2 多類繼承
- 子類沒有覆蓋父類的虛函數

子類的虛函數放在第一張?zhí)摵瘮当碇?,緊跟著第一個父類的虛函數
如果每個父類都有虛函數,則有幾個父類就有幾張?zhí)摵瘮当?/p>
- 子類覆蓋父類的虛函數

父類的虛函數被子類覆蓋后,則該子類對應的重載函數的位置在被覆蓋的父類函數的位置上。(如果父類沒有該虛函數,則不用被覆蓋)
父類的虛函數被子類覆蓋后,則父類指針指向該子類對象時,調用的f()便是子類中重載的f()
示例
#include <iostream>
using namespace std;
class Person1{
public:
virtual void f(){}
virtual void g(){}
virtual void h(){}
virtual ~Person1(){}
};
class Person2{
public:
virtual void f(){}
virtual void g(){}
virtual void h(){}
void a(){ // 成員函數,不需要重載
cout << "class Person2" << endl;
}
virtual ~Person2(){}
};
class Person3{
public:
virtual void g(){}
virtual void h(){}
virtual ~Person3(){}
};
class Bag:public Person1, public Person2, public Person3{
public:
void f(){
cout << "Bag f()" << endl;
}
void g(){
cout << "Bag g()" << endl;
}
void a(){
cout << "Class Bag" << endl;
}
};
int main(int argc, char const *argv[])
{
Person3* p3 = new Bag;
//p3->f(); // P3 沒有成員函數f()
// 多態(tài)首先得是 父類有虛函數,其次是子類要定義該函數的重載
// 如果父類的虛函數改為成員函數,則子類無法進行重載,即無法實現多態(tài)
delete p3;
p3 = NULL;
Person1* p1 = new Bag;
p1->f();
delete p1;
p1 = NULL;
Person2* p2 = new Bag;
p2->a();
delete p2;
p2 = NULL;
return 0;
}
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
VisualStudio2022制作多項目模板及Vsix插件的實現
本文主要介紹了VisualStudio2022制作多項目模板及Vsix插件的實現,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-06-06
C語言中((type *)0) 和(type *0)區(qū)別小結
((type *)0)?和?(type *0)?在 C 和 C++ 中有不同的含義和用途,本文主要介紹了C語言中((type *)0) 和(type *0)區(qū)別,具有一定的參考價值,感興趣的可以了解一下2024-08-08

