虚函数
https://blog.csdn.net/weixin_38952721/article/details/100130983
虚函数的写法
一般是对于基类的某个成员函数
vitrual void function()
当基类的成员函数被指定为虚函数后,派生类的同名同参函数一般也被认为是虚函数,但是为了程序的清晰,一般也加上vitrual
虚函数的作用
为了解决一个基类的指针当指向派生类对象时可以调用派生类对象的函数而不需要再转化为派生类指针
这与派生类指针指向派生类对象,调用其成员函数不同
基类指针也只能调用自己的成员函数不能调用派生类的非虚函数
虚函数的实现方式
- 在C++的标准规格说明书中说到,编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)
假设我们有这样的一个类:
class Base {
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
};
按照上面的说法,我们可以通过Base的实例来得到虚函数表。 下面是实际例程:
typedef void(*Fun)(void);
Base b;
Fun pFun = NULL;
cout << "虚函数表地址:" << (int*)(&b) << endl;
cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;
/这里的一点争议的个人看法/
原文认为(int*)(&b)
是虚表的地址,而很多网友都说,(包括我也认为):(int *)*(int*)(&b)
才是虚表地址
而(int*)*((int*)*(int*)(&b))
; 才是虚表第一个虚函数的地址。
其实看后面的调用pFun = (Fun)*((int*)*(int*)(&b));
就可以看出,*((int*)*(int*)(&b));
转成函数指针给pFun,然后正确的调用到了虚函数virtual void f()。
// Invoke the first virtual function
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
类的大小
- 与类大小有关的因素:普通成员变量,虚函数,继承(单一继承,多重继承,重复继承,虚拟继承)
- 与类大小无关的因素:静态成员变量,静态成员函数及普通成员函数
虚函数表指针(vfptr)(可能有多个,因为多继承)+成员变量(基类的+自己的)+内存对齐+虚拟继承的基类指针(vbptr)