虛函數揭祕
虛函數是什麼?
虛函數就是在類中定義的加了關鍵字virtual的函數,我們知道在類中定義普通函數,四大函數並不會影響類的大小。
那麼我們來看下在空類中定義一個虛函數會不會影響類的大小?
#include<iostream>
using namespace std;
class Base{
// 虛函數就是加了關鍵字的函數
virtual void func1(){
cout<<"fun2 -----" <<endl;
}
};
int main(){
cout<< "size of base:" << sizeof(Base) << endl;
}
我們可以看到上面的大小變成了8,那麼爲什麼變成8 了呢?編譯器幫我們做了什麼?
虛函數的原理
對於一個類而言,在類中定義一個虛函數,那麼編譯器會幫我們生產一個虛函數指針。放到this指針指向的第一個元素位置,後面再跟類的成員。
#include<iostream>
using namespace std;
class Base{
// 虛函數就是加了關鍵字的函數
int a;
virtual void func1(){
cout<<"fun2 -----" <<endl;
}
};
int main(){
cout<< "size of base:" << sizeof(Base) << endl;
}
對於上面的類大小輸出爲16,虛函數指針佔8,int佔4個字節,同時對齊佔用了4個字節。
那麼如果我們在一個類中定義了多個虛函數呢?虛函數指針是一個? 還是多個呢?
事實證明多個虛函數也只會有一個虛函數指針。那麼虛函數指針是怎麼和真實的函數產生聯繫的呢?實際上編譯器維護了一張虛函數表。虛函數表裏面存放了函數的地址,函數地址也可以稱之爲函數指針。
如下圖:
我們可以通過指針來直接調用虛函數 指針是無比強大的
#include<iostream>
using namespace std;
class Base{
// 虛函數就是加了關鍵字的函數
int a;
virtual void func1(){
cout<<"fun1 -----" <<endl;
}
virtual void func2(){
cout<<"fun2 -----" <<endl;
}
};
typedef void (*func_ptr)() ;
int main(){
cout<< "size of base:" << sizeof(Base) << endl;
Base b;
Base *ptr = &b;
long *virtual_ptr = (long *)ptr;
cout << "首地址: "<< virtual_ptr <<" 虛函數表地址 "<< *virtual_ptr << endl;
long address = *virtual_ptr;
func_ptr v1 = (func_ptr)(*(long*)address);
func_ptr v2 = (func_ptr)(*(((long*)address)+1));
v1();
v2();
}
上面代碼執行效果: