C++中的虚函数与纯虚函数
文章目錄
- 1 C++中的虛函數(shù)
- 1.1 虛函數(shù)
- 1.2 單個(gè)類的虛函數(shù)表
- 1.3 使用繼承的虛函數(shù)表
- 1.4 多重繼承的虛函數(shù)表
- 2 C++中的純虛函數(shù)
1 C++中的虛函數(shù)
1.1 虛函數(shù)
虛函數(shù)的定義:
- 在函數(shù)的返回類型之前使用virtual。
- 只在成員函數(shù)的聲明中添加virtual, 在成員函數(shù)的實(shí)現(xiàn)中不要加virtual。
虛函數(shù)的繼承:
- 如果某個(gè)成員函數(shù)被聲明為虛函數(shù),那么它的子類【派生類】,以及子類的子類中,所繼承的這個(gè)成員函數(shù),也自動(dòng)是虛函數(shù)。
- 如果在子類中重寫這個(gè)虛函數(shù),可以不用再寫virtual, 但是仍建議寫virtual, 更可讀!
C++中通過虛函數(shù)實(shí)現(xiàn)多態(tài)。
1.2 單個(gè)類的虛函數(shù)表
代碼如下:
#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 << "非虛函數(shù):Father::func4" << endl; } public: //為了便于測(cè)試,特別該用publicint x = 100;int y = 200;static int z; };typedef void (*func_t)(void); int Father::z = 1; int main(void) {Father father;// 含有虛函數(shù)的對(duì)象的內(nèi)存中,最先存儲(chǔ)的就是“虛函數(shù)表”cout << "對(duì)象地址:" << (int*)&father << endl;int* vptr = (int*)*(int*)&father;cout << "虛函數(shù)表指針vptr:" << vptr << endl;cout << "調(diào)用第1個(gè)虛函數(shù): ";((func_t) * (vptr + 0))();cout << "調(diào)用第2個(gè)虛函數(shù):";((func_t) * (vptr + 1))();cout << "調(diào)用第3個(gè)虛函數(shù): ";((func_t) * (vptr + 2))();cout << "第1個(gè)數(shù)據(jù)成員的地址: " << endl;cout << &father.x << endl;cout << std::hex << (int)&father + 4 << endl;cout << "第1個(gè)數(shù)據(jù)成員的值:" << endl;cout << std::dec << father.x << endl;cout << *(int*)((int)&father + 4) << endl;cout << "第2個(gè)數(shù)據(jù)成員的地址: " << endl;cout << &father.y << endl;cout << std::hex << (int)&father + 8 << endl;cout << "第2個(gè)數(shù)據(jù)成員的值:" << endl;cout << std::dec << father.y << endl;cout << *(int*)((int)&father + 8) << endl;cout << "sizeof(father)==" << sizeof(father) << endl;Father father2;cout << "father的虛函數(shù)表:";cout << *(int*)(*(int*)&father) << endl;cout << "father2的虛函數(shù)表:";cout << *(int*)(*(int*)&father2) << endl;system("pause");return 0; }執(zhí)行效果:
VS的對(duì)象內(nèi)存分布分析:
項(xiàng)目的命令行配置中添加: /d1 reportSingleClassLayoutFather
手繪內(nèi)存分布:
結(jié)果分析:
- 對(duì)象內(nèi),首先存儲(chǔ)的是“虛函數(shù)表指針”,又稱“虛表指針”。然后再存儲(chǔ)非靜態(tài)數(shù)據(jù)成員。
- 對(duì)象的非虛函數(shù),保存在類的代碼中!
- 對(duì)象的內(nèi)存,只存儲(chǔ)虛函數(shù)表和數(shù)據(jù)成員(類的靜態(tài)數(shù)據(jù)成員,保存在數(shù)據(jù)區(qū)中,和對(duì)象是分開存儲(chǔ)的)。
- 添加虛函數(shù)后,對(duì)象的內(nèi)存空間不變!僅虛函數(shù)表中添加條目。多個(gè)對(duì)象,共享同一個(gè)虛函數(shù)表!
1.3 使用繼承的虛函數(shù)表
首先看如下示例代碼:
#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 << "非虛函數(shù):Father::func4" << endl; } public: //為了便于測(cè)試,特別該用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;// 含有虛函數(shù)的對(duì)象的內(nèi)存中,最先存儲(chǔ)的就是“虛函數(shù)表”cout << "son對(duì)象地址:" << (int*)&son << endl;int* vptr = (int*)*(int*)&son;cout << "虛函數(shù)表指針vptr:" << vptr << endl;for (int i = 0; i < 4; i++) {cout << "調(diào)用第" << i + 1 << "個(gè)虛函數(shù):";((func_t) * (vptr + i))();}for (int i = 0; i < 2; i++) {// +4 是因?yàn)橄却鎯?chǔ)了虛表指針cout << *(int*)((int)&son + 4 + i * 4) << endl;}system("pause");return 0; }執(zhí)行效果:
內(nèi)存分布:
子類虛函數(shù)表的構(gòu)建過程:
1.4 多重繼承的虛函數(shù)表
代碼如下:
#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 << "非虛函數(shù):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: //為了便于測(cè)試,使用public權(quán)限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 << "第一個(gè)虛函數(shù)表指針:" << vptr << endl;for (int i = 0; i < 4; i++) {cout << "調(diào)用第" << i + 1 << "個(gè)虛函數(shù):";((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 << "調(diào)用第" << i + 1 << "個(gè)虛函數(shù):";((func_t) * (vptr2 + i))();}for (int i = 0; i < 2; i++) {cout << *(int*)((int)&son + 16 + i * 4) << endl;}system("pause");return 0; }執(zhí)行結(jié)果:
VS分析:
內(nèi)存分布:
2 C++中的純虛函數(shù)
純虛函數(shù)是指只定義原型的成員函數(shù)。一個(gè)C++類中存在純虛函數(shù)就成為了抽象類。
純虛函數(shù)的語法規(guī)則:
能夠?qū)⒏割惖奈鰳?gòu)函數(shù)聲明為純虛函數(shù)?
可以的,當(dāng)我們將符類的析構(gòu)函數(shù)聲明為純虛時(shí),仍然需要給出父類析構(gòu)函數(shù)的實(shí)現(xiàn),否則鏈接報(bào)錯(cuò)。此時(shí)父類仍然是抽象類,由于有了虛函數(shù),就可以實(shí)現(xiàn)多態(tài),使用父類指針釋放空間時(shí)可以正確的調(diào)用析構(gòu)函數(shù)。
參考資料:
總結(jié)
以上是生活随笔為你收集整理的C++中的虚函数与纯虚函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算器用户界面与业务逻辑的分离
- 下一篇: 在千叶眼镜门店内验光是免费的吗?