C++中的虚函数与纯虚函数
生活随笔
收集整理的這篇文章主要介紹了
C++中的虚函数与纯虚函数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1 C++中的虛函數
- 1.1 虛函數
- 1.2 單個類的虛函數表
- 1.3 使用繼承的虛函數表
- 1.4 多重繼承的虛函數表
- 2 C++中的純虛函數
1 C++中的虛函數
1.1 虛函數
虛函數的定義:
- 在函數的返回類型之前使用virtual。
- 只在成員函數的聲明中添加virtual, 在成員函數的實現中不要加virtual。
虛函數的繼承:
- 如果某個成員函數被聲明為虛函數,那么它的子類【派生類】,以及子類的子類中,所繼承的這個成員函數,也自動是虛函數。
- 如果在子類中重寫這個虛函數,可以不用再寫virtual, 但是仍建議寫virtual, 更可讀!
C++中通過虛函數實現多態。
1.2 單個類的虛函數表
代碼如下:
#include <iostream> using namespace std;class Father { public:virtual void func1() { cout << "Father::func1" << endl; }virtual void func2() { cout << "Father::func2" << endl; }virtual void func3() { cout << "Father::func3" << endl; }void func4() { cout << "非虛函數:Father::func4" << endl; } public: //為了便于測試,特別該用publicint x = 100;int y = 200;static int z; };typedef void (*func_t)(void); int Father::z = 1; int main(void) {Father father;// 含有虛函數的對象的內存中,最先存儲的就是“虛函數表”cout << "對象地址:" << (int*)&father << endl;int* vptr = (int*)*(int*)&father;cout << "虛函數表指針vptr:" << vptr << endl;cout << "調用第1個虛函數: ";((func_t) * (vptr + 0))();cout << "調用第2個虛函數:";((func_t) * (vptr + 1))();cout << "調用第3個虛函數: ";((func_t) * (vptr + 2))();cout << "第1個數據成員的地址: " << endl;cout << &father.x << endl;cout << std::hex << (int)&father + 4 << endl;cout << "第1個數據成員的值:" << endl;cout << std::dec << father.x << endl;cout << *(int*)((int)&father + 4) << endl;cout << "第2個數據成員的地址: " << endl;cout << &father.y << endl;cout << std::hex << (int)&father + 8 << endl;cout << "第2個數據成員的值:" << endl;cout << std::dec << father.y << endl;cout << *(int*)((int)&father + 8) << endl;cout << "sizeof(father)==" << sizeof(father) << endl;Father father2;cout << "father的虛函數表:";cout << *(int*)(*(int*)&father) << endl;cout << "father2的虛函數表:";cout << *(int*)(*(int*)&father2) << endl;system("pause");return 0; }執行效果:
VS的對象內存分布分析:
項目的命令行配置中添加: /d1 reportSingleClassLayoutFather
手繪內存分布:
結果分析:
- 對象內,首先存儲的是“虛函數表指針”,又稱“虛表指針”。然后再存儲非靜態數據成員。
- 對象的非虛函數,保存在類的代碼中!
- 對象的內存,只存儲虛函數表和數據成員(類的靜態數據成員,保存在數據區中,和對象是分開存儲的)。
- 添加虛函數后,對象的內存空間不變!僅虛函數表中添加條目。多個對象,共享同一個虛函數表!
1.3 使用繼承的虛函數表
首先看如下示例代碼:
#include <iostream> using namespace std;class Father { public:virtual void func1() { cout << "Father::func1" << endl; }virtual void func2() { cout << "Father::func2" << endl; }virtual void func3() { cout << "Father::func3" << endl; }void func4() { cout << "非虛函數:Father::func4" << endl; } public: //為了便于測試,特別該用publicint x = 100;int y = 200; };class Son : public Father { public:void func1() { cout << "Son::func1" << endl; }virtual void func5() { cout << "Son::func5" << endl; } };typedef void (*func_t)(void);int main(void) {Father father;Son son;// 含有虛函數的對象的內存中,最先存儲的就是“虛函數表”cout << "son對象地址:" << (int*)&son << endl;int* vptr = (int*)*(int*)&son;cout << "虛函數表指針vptr:" << vptr << endl;for (int i = 0; i < 4; i++) {cout << "調用第" << i + 1 << "個虛函數:";((func_t) * (vptr + i))();}for (int i = 0; i < 2; i++) {// +4 是因為先存儲了虛表指針cout << *(int*)((int)&son + 4 + i * 4) << endl;}system("pause");return 0; }執行效果:
內存分布:
子類虛函數表的構建過程:
1.4 多重繼承的虛函數表
代碼如下:
#include <iostream>using namespace std;class Father { public:virtual void func1() { cout << "Father::func1" << endl; }virtual void func2() { cout << "Father::func2" << endl; }virtual void func3() { cout << "Father::func3" << endl; }void func4() { cout << "非虛函數:Father::func4" << endl; } public:int x = 200;int y = 300;static int z; };class Mother { public:virtual void handle1() { cout << "Mother::handle1" << endl; }virtual void handle2() { cout << "Mother::handle2" << endl; }virtual void handle3() { cout << "Mother::handle3" << endl; } public: //為了便于測試,使用public權限int m = 400;int n = 500; };class Son : public Father, public Mother { public:void func1() { cout << "Son::func1" << endl; }virtual void handle1() { cout << "Son::handle1" << endl; }virtual void func5() { cout << "Son::func5" << endl; } };int Father::z = 0;typedef void(*func_t)(void);int main(void) {Son son;int* vptr = (int*) * (int*)&son;cout << "第一個虛函數表指針:" << vptr << endl;for (int i = 0; i < 4; i++) {cout << "調用第" << i + 1 << "個虛函數:";((func_t) * (vptr + i))();}for (int i = 0; i < 2; i++) {cout << *(int*)((int)&son + 4 + i * 4) << endl;}int* vptr2 = (int*) * ((int*)&son + 3);for (int i = 0; i < 3; i++) {cout << "調用第" << i + 1 << "個虛函數:";((func_t) * (vptr2 + i))();}for (int i = 0; i < 2; i++) {cout << *(int*)((int)&son + 16 + i * 4) << endl;}system("pause");return 0; }執行結果:
VS分析:
內存分布:
2 C++中的純虛函數
純虛函數是指只定義原型的成員函數。一個C++類中存在純虛函數就成為了抽象類。
純虛函數的語法規則:
能夠將父類的析構函數聲明為純虛函數?
可以的,當我們將符類的析構函數聲明為純虛時,仍然需要給出父類析構函數的實現,否則鏈接報錯。此時父類仍然是抽象類,由于有了虛函數,就可以實現多態,使用父類指針釋放空間時可以正確的調用析構函數。
參考資料:
總結
以上是生活随笔為你收集整理的C++中的虚函数与纯虚函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算器用户界面与业务逻辑的分离
- 下一篇: C++中流的基本概念