virtual的位置
- 修饰成员方法是虚函数
- 修饰继承方式,就是虚继承。被虚继承的类,称为虚基类
查看如下代码
class A
{
public:
private:
int ma;
};
class B : virtual public A
{
public:
private:
int mb;
};
通过vs命令行的 /d1reportSingleClassLayoutB 查看B的类布局
发生虚继承时,先以没有虚继承时看,类布局最开始是从基类继承而来的成员,若为虚继承时,则把继承而来的成员放到末尾,顶部添加一个vbptr
(虚基类指针)
vbptr
指向vbtable
,vbtable
第一行存vbptr
的偏移量
第二行存vbptr
到虚基类数据之间的偏移量(即ma — vbptr)
有虚继承且有虚函数时类的大小
class A
{
public:
virtual void func(){}
private:
int ma;
};
class B : virtual public A
{
public:
private:
int mb;
};
int main()
{
cout << sizeof B << endl; // 16 , ma, mb, vfptr, vbptr
return 0;
}
虚继承时delete会出现问题
有如下代码
#include <iostream>
#include <string>
using namespace std;
class A
{
public:
virtual void func(){ cout << "call A::func" << endl; }
void operator delete(void* ptr)
{
cout << "operator delete p:" << ptr << endl;
free(ptr);
}
private:
int ma;
};
class B : virtual public A
{
public:
void func() { cout << "call B::func" << endl; }
void* operator new(size_t size)
{
void* p = malloc(size);
cout << "operator new p:" << p << endl;
return p;
}
private:
int mb;
};
int main()
{
A* p = new B();
cout << "main p:" << p << endl;
p->func();
delete p;
return 0;
}
运行时会出现错误,打印如下
首先,new B() 得到的最终B的类布局如下
vftable
第一行-8,表示从vfptr
位置-8到类起始地址
new
返回的地址必然是虚基类的起始地址,而实际分配的类空间从014F0FC8
开始,而delete
时却是从下面的014F0FD0
释放内存。所以报错
但是在linux
下的g++则不会出错