網站首頁 編程語言 正文
代碼描述:定義一個Person類為基類,ChinesePer 類與EnglishPer類都繼承于此基類。
class Person
{
public:
void speak() {
cout << "說人話" << endl;
}
private:
int m_type = 1 ;
};
class ChinesePer :public Person {
public:
void speak() {
cout << "說中國話chinese..." << endl;
}
};
class EnglishPer :public Person {
public:
void speak() {
cout << "說英國話english..." << endl;
}
};
先看看此時各個類占用的內存信息:
int main() {
int person_size = sizeof(Person);
int Chineseper_size = sizeof(ChinesePer);
int Englishper = sizeof(EnglishPer);
}
可以看到三個類的大小都為4個字節,占用的情況就是 類中的m_type變量。
將基類中的 speak() 函數加上virtual關鍵字 ,成為虛函數后再次查看內存字節大小:
可以看到多出了4個字節大小的空間(X86),三個類的大小都為 8。其實就是多出了一個指針的大小,4個字節 ,創建一個子類對象就可以明顯看出來:
可以得出結論一:繼承過來的成員變量 m_type(4個字節) + _vfptr(4個字節) = 8個字節。
繼續探索虛函數表的原理, 創建以下子類對象并通過父類指針指向子類對象調用speak函數發生多態:
int main(){
ChinesePer chs;
ChinesePer chs2;
EnglishPer eng;
Person *ptr = &chs; //父類指針指向子類對象
Person *ptr1 = &chs2;
Person *ptr2 = ŋ
ptr->speak();
ptr1->speak();
ptr2->speak();
}
以上代碼執行后會發生多態:
此時我們看看三個對象的內存分布:
用圖片簡要描述一下就是:
在這里可以先得到結論二: 同一個子類的所有對象共享一個虛函數表,指向虛函數表的指針_vptr是相同的。
在內存分布上查看一下 eng對象的虛函數指針地址情況:
可以看到該虛函數指針的地址上的值,存放的正是 該子類中的重寫函數 speak()函數的地址。
如果把這個地址的值,修改為 Chineseper 類中的重寫函數speak() 的地址值,會發生什么?
手動修改了eng對象中虛函數指針內的地址值,將改值本來是存放的是 EnglishPer 類中的speak() 函數的地址,現在更改為 ChinesePer 類中speak() 函數的地址。
單步走發生多態:
至此可以得出結論三:
當基類函數加了virtual 關鍵字后,虛函數的調用方法是間接調用:先查虛函數表的地址(也就是指向虛函數表的指針 _vptr),再查虛函數表中的虛函數指針。
不妨在基類繼續添加兩個虛函數
class Person
{
public:
virtual void speak() {
cout << "說人話" << endl;
}
virtual void eat() {
cout << "吃飯" << endl;
}
virtual void sleep() {
cout << "睡覺" << endl;
}
private:
int m_type =1 ;
};
子類只重寫了speak函數,查看一下chs對象的虛函數指針地址存放的值:
的確存放的還是各個函數的地址,且是連續存放的,因此在進行查表調用虛函數的時候,也是每移動4個字節指向的就是一個函數的指針地址。
可以簡要描述一下形式就很直觀了:
總結:
1.增加了virtual 關鍵字的對象頭部4個字節是一個指針,指向了虛函數表的地址(單繼承情況下)。
2.同一個子類的所有對象共享一個虛函數表,指向虛函數表的指針_vptr是相同的。
3.當基類函數加了virtual 關鍵字后,虛函數的調用方法是間接調用:先查虛函數表的地址(也就是指向虛函數表的指針 _vptr),再查虛函數表中的虛函數指針。
原文鏈接:https://blog.csdn.net/Huuaaaaa/article/details/128265524
相關推薦
- 2023-07-14 express token的一個用法
- 2022-03-03 el-form動態表單切換導致的校驗bug(v-if、v-show導致校驗失效的bug)
- 2022-03-08 Docker自定義網絡詳細介紹_docker
- 2023-01-13 Qt中QList與QLinkedList類的常用方法總結_C 語言
- 2024-03-21 SpringBoot +MyBatis批量插入數據
- 2022-08-21 Caffe卷積神經網絡solver及其配置詳解_python
- 2022-02-13 使用paddlepaddle進行手寫數字識別
- 2022-06-02 python?離散點圖畫法的實現_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支