虚函数揭秘
虚函数是什么?
虚函数就是在类中定义的加了关键字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();
}
上面代码执行效果: