虛函數的表現形式
用子類初始化父類指針, 調用虛函數時, 仍然調用的是子類的虛函數
測試代碼如下
#include <iostream>
#include <string.h>using namespace std;class A
{
public:void test() { cout << 'a' << endl; };virtual void test2 (){ cout << 'a' << endl; };
};class B : public A
{
public:void test() { cout << 'b' << endl; };virtual void test2(){ cout << 'b' << endl; };
};int main()
{A* a = new B();a->test();a->test2();a->A::test2();
}
輸出結果是
a
b
a
虛函數的實現方式
虛函數表
實現的核心是虛函數表, 每個包含虛函數的類都包含一個虛表, 并且如果該類被繼承, 子類也會生成一個自己的虛表.
虛函數表指針
虛函數表是類的, 不是某個具體對象的, 同一個類的所有對象, 都使用同一張虛表, 那么, 對象
和類的虛表
是如何綁定
在一起的呢?
類
內部包含一個虛表指針__vptr
, 指向虛函數表, 在編譯階段就已經生成. 所以當對象創建時, 便擁有了這個指向類的虛表的指針
關鍵問題
那么問題又來了, 用子類去初始化父類指針, 父類指針是指向父類部分, 為什么會調用子類的虛函數表呢?
C++中虛函數的作用是什么?它應該怎么用呢?
這篇文章里寫的很好, 大概意思就是, 直接調用虛函數的時候, 其實調用的不是真正的虛函數, 而是一個叫CallVirtualFun
的代碼. 這段代碼會用來獲取真正虛函數地址, 最后調用虛函數.
個人認為這些CallVirtualFun
里面的內容都是同樣的邏輯, 找到實例真正的虛函數指針, 然后在表中找到和自己同名的函數指針, 并執行.
其他問題
我們把經過虛表調用虛函數的過程稱為動態綁定,其表現出來的現象稱為運行時多態。
動態綁定區別于傳統的函數調用,傳統的函數調用我們稱之為靜態綁定,即函數的調用在編譯階段就可以確定下來了。