为什么要引入虚拟继承
虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。这样一个类D的对象在访问继承的类A中的成员时就会出现二义性问题。如下面程序:
在31行cout<<a会提示Error:D::a不明确。这是因为所有A的成员在D中都是成对出现的。这时就需要用到虚继承来解决这种二义性。将B、C对A的继承定义为虚拟继承就可以了。
通过下面四种情况来说明虚继承与非虚继承的区别:
第一种情况: 第二种情况:
class a class a
{ {
virtual void func(); virtual void func();
}; char x;
};
class b:public virtual a class b :public class a
{ {
virtual void foo(); virtual void foo();
}; };
第三种情况 第四种情况
class a class a
{ {
virtual void func(); virtual void func();
}; char x;
class b:publicvirtual a };
{ class b:public a
virtual void foo() {
} virtual void foo()
}
如果对这四种情况分别求sizeof(a),sizeof(b)。结果是什么样的呢?下面是输出结果:(在vc6.0中运行)
第一种:4,12
第二种:4,4
第三种:8,16
第四种:8,8
注:上述各类中的各成员在内存中排列顺序未必为图中所示。
例二
#include <iostream>
using namespace std;
class B
{
public:
int i;
virtual void vB(){cout<<"B::vB"<<endl;}
void fB(){cout<<"B::fB"<<endl;}
};
class D1 : virtual public B
{
public:
int x;
virtual void vD1(){cout<<"D1::vD1"<<endl; }
void fD1(){cout<<"D1::fD1"<<endl;}
};
class D2 : virtual public B
{
public:
int y;
void vB(){cout<<"D2::vB"<<endl;}
virtual void vD2(){cout<<"D2::vD2"<<endl;}
void fD2(){cout<<"D2::fD2"<<endl;}
};
class GD : public D1,public D2
{
public:
int a;
void vB(){cout<<"GD::vB"<<endl;}
void vD1(){cout<<"GD::vD1"<<endl;}
virtual void vGD(){cout<<"GD::vGD"<<endl;}
void fGD(){cout<<"GD::fGD"<<endl;}
};
2)类图:
3)内存结构:
基类B:
vfptrB (指向B::fB(),B::vB()) |
int i |
类D1虚继承B:
vfptrD1 (指向D1::fD1(), D1::vD1()) |
vbptrD1 |
int x |
vfptrB (指向B::fB(),B::vB()) |
int i |
类D2虚继承B:
vfptrD2 (指向D2::fB(), D2::fD2(), D2::vD2()) |
vbptrD2 |
int y |
vfptrB (指向B::fB(),B::vB()) |
int i |
类GD多重继承D1,D2(不是虚继承):
vfptrD1 (指向D1::fD1(), GD::vD1(),GD::fGD(), GD::vGD()) |
vbptrD1 |
int x |
vfptrD2 (指向GD::fB(), D2::fD2(), D2::vD2()) |
vbptrD2 |
int y |
vfptrB (指向GD::fB(),B::vB()) |
int i |
Int a |
所以sizeof(GD)=9*4=36个字节。