c++ 多重继承歧义及其解决办法

来源:互联网 发布:mac客人用户是什么 编辑:程序博客网 时间:2024/06/07 10:47

        关于c++中多重继承该不该使用的争论不是我们关注的问题,但是现实世界很多模型确实是多重继承类别。和单一继承相比,它比较复杂,也不太好理解,而且多基派生可能会引起二义性。下面我们就说说多重继承可能的二义性和解决办法。

       先看看没有共同基类的多基派生如何引起二义性。这种继承大致如图所示

这时候有个问题就是假如两个基类有同名的成员,编译器就无法知道要访问哪一个类的成员了,解决的方法就是加上作用域限定符,准确告诉编译器这个成员属于哪个类中的。用一个非常简单的例子代码演示下

#include <iostream>using namespace std;class Base1 {public:int i;};class Base2 {public:int i;};class Derived : public Base1, public Base2 {};int main() {Derived d;//下面这样的用法就会产生错误,编译器不知道i到底属于哪个基类//d.i = 1;//加上类名限定符解决d.Base1::i = 1;d.Base2::i = 2;system("pause");return 0;}
        还有一个多基派生的情况就是含有共同基类(所谓的菱形继承)。

        类似于这种继承,由于Base1和Base2都继承Base,那Base中的成员会被拷贝到两个派生类中,这时候Derived又同时继承Base1和Base2,要是使用基类的成员,就是出现二义性,编译器无法准确知道成员到底属于谁。这种歧义的解决方法是继承的时候将继承自共同基类声明为virtual公有继承。这就是虚基类,这样引用中就只有一份基类的成员拷贝了。还是一个非常简单的例子

#include <iostream>using namespace std;class Base {public:int i;};class Base1 : virtual public Base {public:int j;};class Base2 : virtual public Base {public:int k;};class Derived : public Base1, public Base2 {public:int sum;};int main() {Derived d;d.i = 1;d.j = 2;d.k = 3;d.sum = d.i + d.j + d.k;cout << d.sum << endl;system("pause");return 0;}
        那到底是如何实现的呢,先看看有共同基类派生时,不使用virtual的派生类大小,代码及运行结果看图

        可以看出来,派生类Derived包含了Base1中的一个int 变量和Base1继承自Base中的一个int 变量,同样也包含了Base2中的一个int 变量和Base2继承自Base中的一个int 变量,所以Derived含有4个int变量,32位机器上正好是16个字节。

        在看看使用虚基类的情况,看图吧

        这种情况的对象内存布局大概是这样


        Base1中应该含有一个指向Base对象4字节虚指针和自己的的一个int变量4字节,就是8字节,同样的原理Base2也应该是8字节,派生类Derived应该是20字节=两个基类的16字节+共同基类4字节。


        多重继承要比单一继承复杂,可能会出现二义性。所以在Java语言中使用接口代替了多重继承。在c++中多重继承主要用于接口继承,接口继承仅仅是在一个派生类中加入了成员函数的声明,貌似Java就是这样的,但是c++并不支持这种做法,因为在c++中所有的继承都是实现继承,但是可以模拟实现,首先声明一个接口类,类中只有声明,没有成员数据和函数体,而且除了虚析构函数外,其余的函数都是纯虚函数,然后从这个接口类派生一个子类并实现基类中声明的函数体。关于实现继承、接口继承和可视继承会在以后有空写文章来介绍下。

0 0
原创粉丝点击