这里主要看看C++在多继承含有虚函数的情况下类的内部成员结构和分布。
类继承体系代码如下,先看看非虚继承的情况:
class Base{
public:
Base(){}
virtual ~Base(){}
virtual void v(){}
void f(){}
public:
int data_Base;
};
class Base1 : public Base{
public:
Base1(){}
virtual ~Base1(){}
virtual void v1(){}
void f1(){}
public:
int data_Base1;
};
class Base2 : public Base{
public:
Base2(){}
virtual ~Base2(){}
virtual void v2(){}
void f2(){}
public:
int data_Base2;
};
class Derived : public Base1, public Base2 {
public:
Derived(){}
virtual ~Derived(){}
virtual void v(){}
virtual void v1(){}
virtual void v2(){}
virtual void v3(){}
void f3(){}
public:
int data_Derived;
};
使用VS2010提供的Command Prompt工具里的"cld1"命令查看类的结构如下:
由此可以看到,Derived类在内存里由低到高地址存储的分别是:
vfptr(虚函数表指针,包含Derived类新增的虚函数以及重写的或未重写的Base1基类的虚函数);
data_Base(Base基类的成员变量);
data_Base1(Base1基类的成员变量);
vfptr(虚函数表指针,包含Derived类重写的或未重写的Base2基类的虚函数);
data_Base(Base基类的成员变量);
data_Base2(Base2基类的成员变量);
data_Derived(Derived基类的成员变量);总共28个字节,以下是测试代码:
int main(void)
{
Base1 base1;
Derived derived;
int *p1 = (int*)(&base1);
int *p2 = (int*)(&derived);
derived.data_Base1 = 3;
derived.data_Base2 = 4;
derived.Base1::data_Base = 1;
derived.Base2::data_Base = 2;
derived.data_Derived = 5;
for (int i = 0; i < 10; i++)
{
cout << hex <<p2<<":"<<hex<<*p2++ << endl;
}
cout << "derived size:" <<dec<< sizeof(derived) << endl;
int a = 0;
cin >> a;
return 0;
}
代码打印从Derived实例内存首地址开始的十个整形数据,结果如下:
与上面分析的一致,可以看出Derived包含了基类Base的两份数据,因此需要使用虚继承去掉公共基类的数据重复,加上虚继承后的类代码如下:
class Base{
public:
Base(){}
virtual ~Base(){}
virtual void v(){}
void f(){}
protected:
float data_Base;
};
class Base1 : virtual public Base{
public:
Base1(){}
virtual ~Base1(){}
virtual void v1(){}
void f1(){}
protected:
float data_Base1;
};
class Base2 : virtual public Base{
public:
Base2(){}
virtual ~Base2(){}
virtual void v2(){}
void f2(){}
protected:
float data_Base2;
};
class Derived : public Base1, public Base2 {
public:
Derived(){}
virtual ~Derived(){}
virtual void v(){}
virtual void v1(){}
virtual void v2(){}
virtual void v3(){}
void f3(){}
protected:
float data_Derived;
};
类结构分析结果如下:
由此可以看到,加上虚继承后Derived类在内存里由低到高地址存储的分别是:
vfptr(虚函数表指针,包含Derived类新增的虚函数以及重写的或为重写的Base1基类的虚函数);
vbptr(Base1基类指向公共基类成分部分的指针)
data_Base1(Base1基类的成员变量);
vfptr(虚函数表指针,包含Derived类重写的或未重写的Base2基类的虚函数);
vbptr(Base2基类指向公共基类成分部分的指针)
data_Base2(Base2基类的成员变量);
data_Derived(Derived基类的成员变量);vtordip(C++虚继承机制历史遗留的成员,始终为0);
vbptr(虚函数表指针,包含Derived类重写的或未重写的Base基类的虚函数);
data_Base(Base公用基类的成员变量)
总共40个字节,以下是测试代码:
int main(void)
{
Base1 base1;
Derived derived;
int *p1 = (int*)(&base1);
int *p2 = (int*)(&derived);
derived.data_Base1 = 3;
derived.data_Base2 = 4;
derived.data_Base = 1;
derived.data_Derived = 5;
for (int i = 0; i < 10; i++)
{
cout << hex <<p2<<":"<<hex<<*p2++ << endl;
}
cout << "derived size:" <<dec<< sizeof(derived) << endl;
int a = 0;
cin >> a;
return 0;
}
OK,与上面分析的一致。