網(wǎng)站首頁 編程語言 正文
1、C++中如何實現(xiàn)多態(tài)
- 基類中先聲明一個虛函數(shù)
- 至少有一個繼承該基類的子類
2、虛函數(shù)實現(xiàn)多態(tài)的原理
- 當一個類中出現(xiàn)虛函數(shù)或著子類繼承了虛函數(shù)時,就會在該類中產(chǎn)生一個虛函數(shù)表(virtual table),虛函數(shù)表實際上是一個函數(shù)指針數(shù)組(在有的編譯器作用下是鏈表),里面的每一個元素對應指向該類中的某一個虛函數(shù)的指針。
- 被該類聲明的對象會包含一個虛函數(shù)表指針(virtual table pointer),指向該類的虛函數(shù)表的地址。
- 虛函數(shù)的調(diào)用過程: 當一個對象要調(diào)用到虛函數(shù)時,先將對象內(nèi)存中的vptr指針(虛函數(shù)表指針)指向定義該類的vtbl(虛函數(shù)表),vtbl再尋找里面的指針指向想要調(diào)用的虛函數(shù),從而完成虛函數(shù)的調(diào)用。
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;}
};
父類對象其在內(nèi)存中布局如下:
- 再定義一個子類,此時并不覆蓋父類的虛函數(shù):
class Bag:public Person{
public:
virtual void i(){cout << "use i()" << endl;}
virtual void j(){cout << "use j()" << endl;}
};
可以看出虛函數(shù)表內(nèi)的虛函數(shù)是按聲明順序進行排序的
父類虛函數(shù)排在子類虛函數(shù)之前
- 當我們把子類中的虛函數(shù)覆蓋掉:(修改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;}
};
子類覆蓋的虛函數(shù),放在父類原先放該虛函數(shù)的位置上。
所以當父類指針指向該子類對象時,會調(diào)用該子類的重載函數(shù)
2.2 多類繼承
- 子類沒有覆蓋父類的虛函數(shù)
子類的虛函數(shù)放在第一張?zhí)摵瘮?shù)表中,緊跟著第一個父類的虛函數(shù)
如果每個父類都有虛函數(shù),則有幾個父類就有幾張?zhí)摵瘮?shù)表
- 子類覆蓋父類的虛函數(shù)
父類的虛函數(shù)被子類覆蓋后,則該子類對應的重載函數(shù)的位置在被覆蓋的父類函數(shù)的位置上。(如果父類沒有該虛函數(shù),則不用被覆蓋)
父類的虛函數(shù)被子類覆蓋后,則父類指針指向該子類對象時,調(diào)用的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(){ // 成員函數(shù),不需要重載
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 沒有成員函數(shù)f()
// 多態(tài)首先得是 父類有虛函數(shù),其次是子類要定義該函數(shù)的重載
// 如果父類的虛函數(shù)改為成員函數(shù),則子類無法進行重載,即無法實現(xiàn)多態(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;
}
總結
原文鏈接:https://blog.csdn.net/weixin_44693625/article/details/117393578
相關推薦
- 2022-10-19 Python?Pandas?修改表格數(shù)據(jù)類型?DataFrame?列的順序案例_python
- 2022-10-16 Python?numpy生成矩陣基礎用法實例代碼_python
- 2022-11-05 Nginx反向代理location和proxy_pass配置規(guī)則詳細總結_nginx
- 2022-05-18 python必備庫Matplotlib畫圖神器_python
- 2022-09-21 Python機器學習庫scikit-learn入門開發(fā)示例_python
- 2022-12-14 PostgreSQL模式匹配與正則表達式方法總結_PostgreSQL
- 2022-07-13 Python內(nèi)建類型float源碼學習_python
- 2022-11-30 Android實現(xiàn)一鍵鎖屏功能_Android
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結構-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支