今天小生学习了虚继承,做了一下总结,不足之处请多多批评指正: 首先,菱形继承有一个父类例如class AA,再有两个子类分别继承AA,如class BB:public AA、class CC:public AA,最后,将BB、CC作为父类继承给子类DD,这就形成了菱形继承。请看以下代码: class AA { public: int _aa; }; class BB: public AA { public: int _bb; }; class CC: public AA { public: int _cc; }; class DD:public BB,public CC { public: int _dd; }; AA类中包含一个int变量_aa,BB、CC分别继承了AA,各自又都有一个int型变量,DD继承了BB和CC,它自己又另外有一个自己的int型变量,请往下看: void Test1() { DD d; d._aa = 1; d._bb = 2; d._cc = 3; d._dd = 4; } 在Test1中定义了一个DD类型的d,分别给d._aa、d._bb、d._cc,d._dd赋值,运行代码发现出现了以下错误: 对_aa的访问不明确,为什么呢?是因为d中包含了一个BB类型和一个CC类型,而它们都继承了AA类型,所以d中包含了两个_aa,当我们直接用d._aa访问时,编译器不知道我们访问的是哪一个,所以出错,这既是菱形继承的二义性,坚决这个问题的一种方法是指定类域,如下图
代码: 上图代码运行后得到右面的结果,大家可以看到,我们给_aa赋值时指定了给BB类型 中的_aa赋值,而CC中的_aa并不会发生变化。这种方法虽然解决了菱形继承的二义性,确没有解决代码冗余的问题,下面给大家介绍另一种方法虚继承,它能够同时解决了这两个问题。虚继承中我们用到了关键字virtual,请看以下代码: class BB:virtual public AA { public: int _bb; }; class CC:virtual public AA { public: int _cc; }; class DD:public BB,public CC { public: int _dd; }; BB与CC在继承AA时在public AA前面加了virtual这个关键字,这样我们再运行下面这段代码时发现原来的错误没有了。 void Test1()
} 这是为什么呢,因为加上virtual后我,DD型变量d在内存中存储方式方式的变化,下图为大家展示了二者的不同: 大家从内存中可以看到前后发生的变化,_aa只有一个了,所以解决了二义性和代码冗余的问题,大家可能会觉得这里占用的内存反而用的多了,并且_bb、_CC上面都多了一个地址,那我们看看这两个地址里面到底有什么:
我们可以看到_bb上面的这个地址里面存了一个十六进制数字14,_cc上面的地址里面存了一个十六进制的数字0c,这是什么呢,这其实是d中包含的BB、CC类型各自的地址到_a地址的偏移量,请看以下代码: DD* pd = new DD; BB* pb = pd; 继承有复制兼容性规则,而虚继承也要满足这个规则,如果没有这两个指针,上述代码运行时_aa与_bb,不在一起,这里也就无法截断赋值,赋值兼容性规则就不满足了,而有了这两个指针,我们这样赋值时,通过这两个指针找到了偏移量,加上偏移量就可以访问到_aa,也就满足了复制兼容性规则。
新闻热点
疑难解答