虛擬函式的呼叫原理
虛擬函式以及虛擬函式表
引言
如果父類與子類有同名的方法,當父類指標指向子類物件時,通過該指標呼叫同名方法,會直接呼叫父類的方法,將父類中該方法定義為虛擬函式則可以解決這個問題,程式碼如下:
#include<iostream>
using namespace std;
class father
{
public:
father()
{
cout << "呼叫father建構函式" << endl;
}
void eat()
{
cout << "我喜歡吃牛肉" << endl;
}
};
class son:public father
{
public:
son()
{
cout << "呼叫son類的建構函式" << endl;
}
void eat()
{
cout << "我喜歡吃羊肉" << endl;
}
};
int main()
{
father* father1;
father1 = new son();
father1->eat();
return 0;
}
執行結果如下:
可以看出當father類指標指向son類物件時呼叫了同名的eat()方法,執行的是father的eat()方法,那麼怎麼樣才能執行son類的eat()方法呢?
實現方法是在father類的eat()方法前加一個virtual關鍵字,使得該函式成為虛擬函式,程式碼如下:
virtual void eat()
{
cout << "我喜歡吃牛肉" << endl;
}
再次執行,結果如下:
可以看到此時執行了子類的eat()方法,
虛擬函式的呼叫原理
繼承一個基類的情況
class father
{
public:
virtual void func1() { cout << "呼叫func1" << endl; }
virtual void func2() { cout << "呼叫func2" << endl; }
virtual void func3() { cout << "呼叫func3" << endl; }
public:
int x = 0;
int y = 2;
};
class son :public father
{
public:
void func1()override { cout << "呼叫son1" << endl; }
virtual void son3() { cout << "呼叫son3" << endl; }
public:
int i = 10;
int j = 20;
};
定義一個子類物件,子類物件的記憶體分佈如下圖:
根據上圖,子類物件son1的第一個成員存放了虛擬函式表的指標,因此可以根據son1的地址取出虛表指標來呼叫虛擬函式,程式碼實現如下:
int* pSon1 = (int*)*(int*)&son1;
cout <<endl<< "呼叫第一個虛擬函式表" << endl;
for (int i = 0; i < 4; i++)
{
(*((func_t*)pSon1+i))();
}
程式碼執行結果(完整程式碼最後附上):
多重繼承的情況
class father
{
public:
virtual void func1() { cout << "呼叫func1" << endl; }
virtual void func2() { cout << "呼叫func2" << endl; }
virtual void func3() { cout << "呼叫func3" << endl; }
public:
int x = 0;
int y = 2;
};
class mother
{
public:
virtual void handle1() { cout << "呼叫handle1" << endl; }
virtual void handle2() { cout << "呼叫handle2" << endl; }
virtual void handle3() { cout << "呼叫handle3" << endl; }
public:
int m = 5;
int n = 8;
};
class son :public father, public mother
{
public:
void func1()override { cout << "呼叫son1" << endl; }
void handle2()override { cout << "呼叫son2" << endl; }
virtual void son3() { cout << "呼叫son3" << endl; }
public:
int i = 10;
int j = 20;
};
在多重繼承的情況下,子類物件的記憶體分佈情況如下圖:
根據上圖可以由物件son1的地址來呼叫虛擬函式表2,程式碼如下:
cout << endl << "呼叫第二個虛擬函式表" << endl;
int *pSon2 = (int*)*((int*)(&son1) + 3);
for (int i = 0; i < 3; i++)
{
(*((func_t*)pSon2 + i))();
}
程式碼執行結果如下圖:
結論
1.在多重繼承的情況下,子類物件會儲存多個虛擬函式表指標(取決於繼承了多少個父類),而且存放順序是根據繼承順序來的
2.子類單獨定義的虛擬函式存放在第一個虛擬函式表的最後一個位置,同樣子類的資料成員也存放在最後
原始碼:https://github.com/1137185761/virtual-function.git
相關文章
- 虛擬函式的實現原理函式
- 虛擬函式,虛擬函式表函式
- 虛擬函式 純虛擬函式函式
- 介面、虛擬函式、純虛擬函式、抽象類函式抽象
- 虛擬函式表-C++多型的實現原理函式C++多型
- [Lang] 虛擬函式函式
- C++建構函式和解構函式呼叫虛擬函式時使用靜態聯編C++函式
- 【C++筆記】虛擬函式(從虛擬函式表來解析)C++筆記函式
- 【C++筆記】虛擬函式(從虛擬函式概念來解析)C++筆記函式
- c++虛擬函式表C++函式
- 虛擬函式與多型函式多型
- C++(虛擬函式實現多型基本原理)C++函式多型
- 內聯(inline)函式與虛擬函式(virtual)的討論inline函式
- 詳細講解函式呼叫原理函式
- C++ 介面(純虛擬函式)C++函式
- C++ 虛擬函式表解析C++函式
- 深入C++成員函式及虛擬函式表C++函式
- 詳解 JS 中 new 呼叫函式原理JS函式
- 虛擬函式的記憶體佈局(上)函式記憶體
- 關於虛擬函式的一些理解函式
- C++多型之虛擬函式C++多型函式
- 抽象基類和純虛擬函式抽象函式
- 外部函式的呼叫函式
- C++虛擬函式學習總結C++函式
- [C#解惑] #1 在建構函式內呼叫虛方法C#函式
- C++之類解構函式為什麼是虛擬函式C++函式
- 基類指標、虛純虛擬函式、多型性、虛析構指標函式多型
- setV:一個管理 Python 虛擬環境的 Bash 函式Python函式
- 詳解C++中的多型和虛擬函式C++多型函式
- C++ 派生類函式過載與虛擬函式繼承詳解C++函式繼承
- 深入探討Function Calling:實現外部函式呼叫的工作原理Function函式
- 子函式呼叫函式
- 函式呼叫棧函式
- vue虛擬dom原理Vue
- 程式碼保護軟體VMP逆向分析虛擬機器指令:指令中包含了函式呼叫虛擬機函式
- 避免對派生的非虛擬函式進行重定義函式
- Java常見知識點彙總(④)——虛擬函式、抽象函式、抽象類、介面Java函式抽象
- C++純虛擬函式簡介及區別C++函式