最近在看《深度探索C++对象模型》这本书的时候,里面第一章提到了虚拟继承,有这么一句话说:“在虚拟继承的情况下,base
class不管在继承串链中被派生多少次,永远只会存在一个实体。”一开始我理解错了,以为这个继承类图体系里面全局只有一个base
class对象,后来查了些资料才知道意思是一个子类中只包含一个bass class对象。
很多东西要有对比才能认识得更深刻,我们这里对比下虚拟继承和普通继承的子类对象的区别,也从而让我们更好地理解文章开头提到的书里的那句话。
虚拟继承样例:
class CTestBase
{
public:
int base_data_;
};class CTestSubject1:virtual class CTestBase
{
public:
int subone_data_;
};class CTestSubject2:virtual class CTestBase
{
public:
int subtwo_data_;
};class CTestDiamond:public CTestSubject1,public CTestSubject2
{
public:
int dia_data_;
};int main()
{
CTestDiamond dia;
dia.base_data_ = 1;
}
上面当中dia.base_data_能够被赋值,再看普通继承的例子。
普通继承样例:
1 class CTestBase
2 {
3 public:
4 int base_data_;
5 };
6
7 class CTestSubject1:public CTestBase
8 {
9 public:
10 int subone_data_;
11 };
12
13 class CTestSubject2:public CTestBase
14 {
15 public:
16 int subtwo_data_;
17 };
18
19 class CTestDiamond:public CTestSubject1,public CTestSubject2
20 {
21 public:
22 int dia_data_;
23 }
24
25 int main()
26 {
27 CTestDiamond dia;
28 dia.base_data_ =1;
29 }
这时候就出问题了,同样的继承结构,但是只不过没有了虚拟继承,我们对dia.base_data_的赋值就不能通过编译了,这是因为没有了虚拟继承,我们的dia对象中有2个base_data_,一个是从CTestSubject1中继承来的,另一个是从CTestSubject2中继承来的。这样一来编译器就不知道具体要给哪个base_data_赋值了,而当我们用虚拟继承时,对象dia中只有一个base_data_,所以显而易见编译器就知道该怎么赋值。这就是那句话的意思,不管继承多少次,永远只会存在一个虚基类的实体。
那我们该怎么在普通继承中对多个base_data_赋值呢?
我们只需要dia.CTestSubject1::base_data_ =
1,这样编译器就知道我们是想给CTestSubject1中的base_data_赋值了。CTestSubject2里面的base_data_也同理。
总结:
通过上面的2个例子,我们很容易看出虚拟继承和普通继承的区别,我觉得学习语言不需要去纠结语法,而应该去理解各种语法用法之间的区别,具体怎么用,只有结合实际中的编程场景,通过分析选择最合适的方式来使用,相信存在即是道理。
当然上面只是从表面来分析虚拟继承和普通继承,更深层次地可以从对象模型和内存布局去理解。
有关C++虚拟继承的简单理解