爲什麼要引入虛擬繼承
虛擬繼承是多重繼承中特有的概念。虛擬基類是爲解決多重繼承而出現的。如:類D繼承自類B1、B2,而類B1、B2都繼承自類A,因此在類D中兩次出現類A中的變量和函數。這樣一個類D的對象在訪問繼承的類A中的成員時就會出現二義性問題。如下面程序:
#include <iostream>
using namespace std;
class A
{
protected:
int a;
public:
A(int m=1)
{
a = m;
cout << "class A " << a << endl;
}
};
class B:public A
{
public:
B(int m=2):A(m)
{
cout << "class B " << a << endl;
}
};
class C:public A
{
public:
C(int m=3):A(m)
{
cout << "class C " << a << endl;
}
};
class D:public B, public C
{
public:
D(int m = 100):B(m)
{
cout << "class D " << a << endl;
cout << "class D " << a << endl;
}
};
int main()
{
D d;
}
編譯時報錯43: error: reference to ‘a’ is ambiguous。這是因爲所有A的成員在D中都是成對出現的。這時就需要用到虛繼承來解決這種二義性。將B、C對A的繼承定義爲虛擬繼承就可以了。
通過下面四種情況來說明虛繼承與非虛繼承的區別:
第一種情況:
class a
{
virtual void func();
}
class b:public virtual a
{
virtual void foo();
}
第二種情況:
class a
{
virtual void func();
}
class b:public a
{
virtual void foo();
}
第三種情況:
class a
{
virtual void func();
char x;
}
class b:public virtual a
{
virtual void foo();
}
第四種情況:
class a
{
virtual void func();
char x;
}
class b:public a
{
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個字節。