• 菱形继承产生的问题及解决


    1.何为菱形继承?

    两个子类继承同一个父类,而又有子类又分别继承这两个子类,就如上图说示。

    #include<stdio.h>
    #include<iostream>
    #include<queue>
    using namespace std;
    
    class A {
    public:
        A(){printf("A create.
    ");}
        int a;
        virtual void fun(){}
    };
    
    class B: public A{
    public:
        B(){printf("B create.
    ");}
        int b;
        virtual void fun1(){}
    };
    
    class C: public A
    {
    public :
        int c;
        C(){printf("C create.
    ");}
        virtual void fun3(){printf("fun3 .
    ");}
    };
    
    class D:public C,public B{
    public:
        int d;
        D(){printf("D create.
    ");}
        virtual void fun3(){printf("fun4 .
    ");}
    }; 
    //二义性问题的开销 
    int main() {
        D *pd=new D;
        printf("%d
    ",sizeof(D));
        getchar();
    }
    View Code

    产生的问题,会产生二义性问题,即对于baseClass的调用要说明作用域的情况:

        D *pd=new D;
        pd->B::a=1;
        pd->C::a=2;
        printf("%d
    ",pd->B::a);
        printf("%d
    ",pd->C::a);

    相当于baseClass在类中有两个,这可能不是我们想要的结果,增加调用的困难,同时也会浪费内存资源。

    这种结构如图:

    可以看到A指向的虚函数表的位置是不一样的!即baseClass有两个实例!

    2.如何解决?

    使用虚拟继承!

    #include<stdio.h>
    #include<iostream>
    #include<queue>
    using namespace std;
    
    class A {
    public:
        A(){printf("A create.
    ");}
        int a;
        virtual void fun(){}
    };
    
    class B:virtual public A{
    public:
        B(){printf("B create.
    ");}
        int b;
        virtual void fun1(){}
    };
    
    class C:virtual public A
    {
    public :
        int c;
        C(){printf("C create.
    ");}
        virtual void fun3(){printf("fun3 .
    ");}
    };
    
    class D:public C,public B{
    public:
        int d;
        D(){printf("D create.
    ");}
        virtual void fun3(){printf("fun4 .
    ");}
    }; 
    //二义性问题的开销 
    int main() {
        D *pd=new D;
        pd->B::a=1;
        pd->C::a=2;
        printf("%d
    ",pd->B::a);
        printf("%d
    ",pd->C::a);
        printf("%d
    ",sizeof(D));
        getchar();
    }
    View Code

    内存布局:

      对于baseClass是公用的,也就是baseClass就实例化了一个对象!想想这会有什么后果?调用B,C的虚函数的时候就一个虚表怎么行,所以有需要对应有两个相应的虚表指向B,C,于是就成了上面的结构了。

      调试观察,果然如此!

      

    总结:可以通过虚拟继承消除二义性,但是虚拟继承的开销是增加虚函数指针。

    参考:C++程序优化

    ps:这时就有疑问了,既然多重继承的会有二义性的问题,为什么编译器不能自己识别并处理呢,也许别人给你写的一个类中与你写的类中同时继承了一个基类(不知情),别人又同时继承了这两个类= =!可能有人会说,多重继承太复杂,一般都用单一继承!也许这就是C++优势有时也是劣势吧= =

  • 相关阅读:
    Arrays类
    异常
    Java日志第53天 2020.8.29
    Java日志第52天 2020.8.28
    Java日志第55天 2020.8.31
    Java日志第54天 2020.8.30
    测试:ATM
    dear mother
    Spring
    People like me
  • 原文地址:https://www.cnblogs.com/huhuuu/p/3496304.html
Copyright © 2020-2023  润新知