精华内容
下载资源
问答
  • C++多继承中二义性问题

    千次阅读 多人点赞 2018-05-24 17:35:46
    在C++,派生类继承基类,对基类成员的访问应该是确定的、唯一的,但是常常会有以下情况导致访问不一致,产生二义性。 1.在继承时,基类之间、或基类与派生类之间发生成员同名时,将出现对成员访问的不确定性——...
        在C++中,派生类继承基类,对基类成员的访问应该是确定的、唯一的,但是常常会有以下情况导致访问不一致,产生二义性。
        1.在继承时,基类之间、或基类与派生类之间发生成员同名时,将出现对成员访问的不确定性——同名二义性。
        2.当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生另一种不确定性——路径二义性。

        1.

                                                                        

    “倒三角”问题——同名二义性

    #include "iostream"
    
    using namespace std;
    
    class Parent_f
    {
    public:
        void show()
        {
            cout<<"This is Parent_f\n";
        }
    };
    class Parent_m
    {
    public:
        void show()
        {
            cout<<"This is Parent_m\n";
        }
    };
    class Son:public Parent_f,public Parent_m
    {
    public:
        void display()
        {
            cout<<"This is son\n";
        }
    };
    int main()
    {
        Son son;
        son.show();
        son.display();
        cout << "Hello world!" << endl;
        return 0;
    }

    上面的代码中,2个父类派生一个子类,但两个父类中都有同名的成员函数。派生出的子类产生二义性问题,编译时会报:

    error: request for member 'show' is ambiguous

        解决方法:

        (1)利用作用域限定符(::),用来限定子类调用的是哪个父类的show()函数

    son.Parent_f::show();
        (2)在类中定义同名成员,覆盖掉父类中的相关成员
    class Son:public Parent_f,public Parent_m
    {
    public:
        void display()
        {
            cout<<"This is son\n";
        }
    
        void show()
        {
            cout<<"show:This is son.\n";
        }
    };


    2.

                                                        

    “菱形”问题——路径二义性

        有最基类A,有A的派生类B、C,又有D同时继承B、C,那么若A中有成员a,那么在派生类B,C中就存在a,又D继承了B,C,那么D中便同时存在B继承A的a和C继承A的a,那么当D的实例调用a的时候就不知道该调用B的a还是C的a,就导致了二义性。

    #include "iostream"
    
    using namespace std;
    
    class Grandpa
    {
    public:
        int year_old;
    };
    
    class Parent_f:public Grandpa {};
    class Parent_m:public Grandpa {};
    
    class Son:public Parent_f,public Parent_m {};
    
    int main()
    {
        Son son;
        son.year_old = 10;
        cout << "Hello world!" << endl;
        return 0;
    }
    

        Grandpa为Parent_f和Parent_m的基类,而Son又继承Parent_f和Parent_m,当Son访问Grandpa的year_old时,会出现二义性错误.

        解决方法:

        (1)使用作用域限定符,指明访问的是哪一个基类的成员。

                注意:不能是Grandpa作用域下限定,因为Son直接基类的基类才是Grandpa,纵使指明了访问Grandpa的成员的话,对于Son来说,还是模糊的,还是具有二义性。

        (2)在类中定义同名成员,覆盖掉父类中的相关成员。

        (3)虚继承、使用虚基类

            教科书上面对C++虚基类的描述玄而又玄,名曰“共享继承”,名曰“各派生类的对象共享基类的的一个拷贝”,其实说白了就是解决多重多级继承造成的二义性问题。父类对祖父类的继承方式改为虚继承,那么子类访问自己从祖父类那里继承过来的成员就不会有二义性问题了,也就是将子类对象里的祖父类对象统一为一个,继承的只有一个祖父类对象,代码如下。

    #include "iostream"
    
    using namespace std;
    
    class Grandpa
    {
    public:
        int year_old;
        void show()
        {
            cout << "year_old:" << year_old <<endl;
        }
    };
    
    class Parent_f:virtual public Grandpa {};
    class Parent_m:virtual public Grandpa {};
    
    class Son:public Parent_f,public Parent_m {};
    
    int main()
    {
        Grandpa grp;
        Parent_f pa_f;
        Parent_m pa_m;
        Son son;
    
        grp.year_old = 100;
        pa_f.year_old = 55;
        pa_m.year_old = 50;
        son.year_old = 10;
    
        grp.show();
        pa_f.show();
        pa_m.show();
        son.show();
        cout << "Hello world!" << endl;
        return 0;
    }

        使用了虚基类的方法,是不是感觉简单方便多了呢








    展开全文
  • 多继承二义性

    千次阅读 2018-10-08 09:45:22
    多继承二义性主要分为两种: 调用不同基类的同名成员时可能出现二义性 访问共同基类的成员可能出现二义性 1、调用不同基类的同名成员时可能出现二义性 class A { public: void setA(int a); int get(); .....

    转自:https://www.cnblogs.com/tenjl-exv/p/7625484.html

    多继承的二义性主要分为两种:

    1. 调用不同基类的同名成员时可能出现二义性
    2. 访问共同基类的成员可能出现二义性

    1、调用不同基类的同名成员时可能出现二义性

    class A
    {
        public:
            void setA(int a);
            int get();
        private:
            int a;
    } ;
    class B
    {
        public:
            void setB(int b);
            int get();
        private:
            int b;
    } ;
    
    class C:public A,public B
    {
        public:
            void setC(int c);
            int getC();
        private:
            int c;
    };

     在执行obj.get();时将是有二义性的。因为类C分别从类A类B继承了两个不同版本的get()成员函数,因此,obj.get();到底调用哪个get()版本,编译器将无从知晓。

    有两种解决方法:

    (1)使用作用域分辨符::加以消除。

    obj.A::get();

    obj.B::get();

    (2)在类C中也定义成员函数get()函数,则有类C的对象obj访问get()函数obj.get()没有二义性,这是因为当派生类中的成员与基类中的成员重名时,派生类中的同名成员将被调用。

    class A
    {
        public:
            void setA(int a);
            int get();
        private:
            int a;
    } ;
    class B
    {
        public:
            void setB(int b);
            int get();
        private:
            int b;
    } ;
    
    class C:public A,public B
    {
        public:
            void setC(int c);
            int get();
                    //此处改为这样    
        private:
            int c;
    };

     2、访问共同基类的成员可能出现二义性

    菱形继承问题

    class A
    {
        public:
            void disp(); 
        private:
            int a;
    };
    
    class B1:public A
    {
        public:
            void dispB1();
        private: 
            int b1;
    };
    class B2:public A
    {
        public:
            void dispB2();
        private: 
            int b2;
    };
    
    class C:public B1,public B2
    {
        public:
            void dispC();
        private: 
            int c;
    };

     

    在此类结构下,如果创建类C的对象c1:

    C c1;

    则下面的两个访问都有二义性:

    c1.disp();

    c1.A::disp();

    不过下面的两条调用语句却是正确的:

    c1.B1::disp();

    c1.B2::disp();

    解决方法:

    采用虚基类的方式,代码如下:

    class A
    {
        public:
            void disp(); 
        private:
            int a;
    };
    
    class B1:virtual public A
    {
        public:
            void dispB1();
        private: 
            int b1;
    };
    class B2:virtual public A
    {
        public:
            void dispB2();
        private: 
            int b2;
    };
    
    class C:public B1,public B2
    {
        public:
            void dispC();
        private: 
            int c;
    };

     

    展开全文
  • 多继承二义性问题

    2020-07-16 22:02:07
    当 A,B两个父类有同名函数时,C调用该函数就会出现二义性。 解决方法: 避免出现同名函数 编码指定具体的那个 c.A::func() C c; c.A::func();//指定A父类的那个 在C重定义func,此A,B的func都被隐藏了 ...

    多继承:一个子类继承多个父类

    class C: public A,public B
    {
    }
    

    当 A,B两个父类中有同名函数时,C调用该函数就会出现二义性。
    解决方法

    1. 避免出现同名函数
    2. 编码指定具体的那个 c.A::func()
    C c;
    c.A::func();//指定A父类的那个
    
    1. 在C中重定义func,此A,B中的func都被隐藏了

    菱形继承问题:B1:A, B2:A, C:B1,B2,此时C调用A的方法时出现二义性问题
    解决办法:
    可以用上述2,3办法,一般用虚继承来解决
    虚继承:

    继承时加virtual

    class B1:virtual public A
    {
    }
    
    class B2:virtual public A
    {
    }
    

    B1,B2虚继承A后,C多继承自B1,B2不会出现二义性
    虚继承在没有二义性问题时不产生任何影响,virtual跟没加一样

    多态:
    (1)从宏观讲,多态就是要实现一套逻辑多种具体适配的执行结果。
    (2)从微观讲,多态就是要一套代码在运行时根据实际对象的不同来动态绑定/跳转执行相匹配的具体函数

    虚函数:
    虚函数是C++实现多态特性的基础,从语法上讲多态特性的基类方法必须是虚函数
    函数前加virtual就是虚函数

    基类中方法声明为virtual,派生类中重新实现同名方法以实现多态,这就叫override(覆盖,重写)

    override(覆盖,重写)和redefining(重定义,隐藏)的区别:
    微观上最大区别就是是否有virtual,宏观上最大区别就是是否表现为多态

    纯虚函数和抽象类:
    纯虚函数如下形式:

    virtual void speak() = 0;
    

    只有原型没有实体的一种虚函数(因为没有需求所以没有实体)
    纯虚函数不占内存

    • 含有纯虚函数的类就是抽象类,不能构建对象
    • 抽象类的子类必须实现基类中的纯虚函数,这样子类才能创建对象,否则子类就还是个抽象类

    虚析构函数:
    析构函数前加virtual,则析构函数变为虚析构函数

    virtual ~A();
    

    基类有1个或多个虚函数时(不要求是纯虚函数),则其析构函数应该声明为virtual(存在虚函数时,不用虚析构函数的话,对象分配在栈上时正常,分配在堆上时出错)

    总结
    (1)虚函数的virtual的价值,就是让成员函数在运行时动态解析和绑定具体执行的函数(编译时不进行具体绑定),这是RTTI(运行时识别)机制的一部分。
    (2)析构函数也是成员函数,加virtual的效果和普通成员函数加virtual没什么本质差异
    (3)加virtual是有开销的,运行时动态绑定不如编译时静态绑定效率高资源消耗优,但是可以多态。

    展开全文
  • 一般来说,在派生类对基类成员的访问应该是唯一的,但是,由于在多继承情况下,可能出现对基类某个成员的访问不唯一性情况,这称为对基类成员访问的多继承二义性问题 分两种情况: first: 派生类的多个基类...

    一般来说,在派生类中对基类成员的访问应该是唯一的,但是,由于在多继承情况下,可能出现对基类中某个成员的访问不唯一性情况,这称为对基类成员访问的多继承二义性问题

    分两种情况:
    first: 派生类的多个基类中调用其同名成员时可能出现二义性
    second:派生类有共同基类时访问公共基类成员可能出现二义性

    例子:

    #include <iostream>
    using namespace std;
    
    class A
    {
    	public:
    	A() {cout << "A constructor called" << endl;}
    };
    class B1 : public A
    {
    	public:
    	B1(){cout << "B1 constructor called" << endl;}
    };
    class B2 : public A
    {
    	public:
    	B2(){cout << "B2 constructor called" << endl;}
    };
    class C : public B1, public B2
    {
    	public:
    	C(){cout << "C constructor called" << endl;}
    };
    
    int main(int argc,char **argv)
    {
    	C cc;
    	system("pause");
    	return 0;
    }
    

    在这里插入图片描述
    在实例化C时,调用了两次基类的构造函数;虚基类的引入解决了此类问题
    修改后的代码如下:

    #include <iostream>
    using namespace std;
    
    class A
    {
    	public:
    	A() {cout << "A constructor called" << endl;}
    };
    class B1 : virtual public A
    {
    	public:
    	B1(){cout << "B1 constructor called" << endl;}
    };
    class B2 : virtual public A
    {
    	public:
    	B2(){cout << "B2 constructor called" << endl;}
    };
    class C : public B1, public B2
    {
    	public:
    	C(){cout << "C constructor called" << endl;}
    };
    
    int main(int argc,char **argv)
    {
    	C cc;
    	system("pause");
    	return 0;
    }
    

    在这里插入图片描述
    有调试结果可得,只调用了一次基类A的构造函数

    展开全文
  • 菱形继承问题和虚继承是如何解决二义性与数据冗余的继承是c++的三大特性之一,其中菱形继承问题是一个值得我们学习和掌握的知识点。 1.什么是菱形继承呢? 菱形继承定义为:两个子类继承同一个父类,而又有子类...
  • 菱形继承我们都知道,C++有单继承和多继承两种继承方式: 单继承:如果一个类只有一个直接基类(也就是父类),我们称这种继承方式为单继承。 多继承:如果一个类有多个父类(2个及其两个以上),我们称这种继承...
  • 本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三一、小鱼)... 例1:定义基类CBase,并定义CBase的派生类CDerived1和CDerived2,在定义CDerived1和CDerived2的派生类CDerived12,观察二义性。 代码
  • 讲解C++多继承

    2008-04-29 15:09:54
    重点描述多继承带来的二义性的问题 以及一些多继承的例子
  • 最近被问到一个关于多继承虚函数表的问题,当时回答是可能存在多个虚函数表,应该是顺序排列的,但具体怎么排列还是有些疑惑的,回答的时候到有点儿心虚。之后查了资料,做了简单的实验,可以确定的是对于继承了多个...
  • c++多继承

    2015-06-03 09:32:00
    所谓多继承是指派生类具有多个基类,派生类与每个基类之间的关系仍可看作是一个单继承。    多继承下派生类的定义格式如下:    class :,,…  {    };    其中
  • Objective-C 的“多继承

    万次阅读 多人点赞 2013-05-24 17:10:43
    但是Objective-C不支持多继承,由于消息机制名字查找发生在运行时而非编译时,很难解决多个基类可能导致的二义性问题。不过其实 Objective-C 也无需支持多继承,我们可以找到如下几种间接实现多继承目的的方法:消息...
  • Objective-C 的“多继承” ...但是Objective-C不支持多继承,由于消息机制名字查找发生在运行时而非编译时,很难解决多个基类可能导致的二义性问题。不过其实 Objective-C 也无需支持多继承,我们可以找
  • IOS之Objective-C 的“多继承

    千次阅读 2013-05-28 19:28:13
    但是Objective-C不支持多继承,由于消息机制名字查找发生在运行时而非编译时,很难解决多个基类可能导致的二义性问题。不过其实 Objective-C 也无需支持多继承,我们可以找到如下几种间接实现多继承目的的方法:
  • 上节课的内容,LR(0)存在冲突。这节课首先提出SLR进行解决。SLR的改进很简单,但还存在冲突。因此又引出LR(1)。 但是,LR(1)的状态过多,于是引出LALR化简、合并其状态。...最后,介绍了二义性与错误处理。
  • 多重继承

    千次阅读 2014-09-16 10:00:24
    在前几篇博客介绍了继承,并且通过几个...需要说明的是多重继承在实际编程并不常用,因为在使用过程容易出现多重继承二义性 为了避免出现多重继承二义性C++引入了虚基类的概念,在Java不允许使用多重继
  • 继承

    2018-07-01 22:22:43
    继承类之间的关系:has-a表示类的包含关系,即一个类的数据成员是已经...由多个类派生一个新的类的方法,称为“多继承”。类的包含和类的继承都是软件重用技术。在许多情况下,程序类的包含结构可以改为继承结构...
  • C++多继承带来的麻烦

    2012-10-01 09:33:58
    继承基类时,在派生类就获得了基类所有的数据成员副本。假如类B 从A1和A2两个类多重继承而来,这样B类就包含A1、A2类的数据成员副本。 考虑如果A1、A2都从某基类派生,该基类称为Base,现在继承关系如下: ...
  • 在很次面试,我发现面试官都喜欢问同一个问题:谈谈你对多态的认识。 遇到这个问题,通常我第一句话就是:多态分为静态多态和动态多态,然后静态多态就是balabala动态多态是巴拉巴拉。关于静态多态这里不再赘述...
  • C++继承关系

    千次阅读 2016-11-08 12:50:15
    C++继承关系 一、继承概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象...
  • C++多继承与菱形缺陷

    千次阅读 2007-12-17 16:02:00
    这是因为多重继承致命的缺陷导致的:1.1.1 菱形缺陷 当继承基类时,在派生类就获得了基类所有的数据成员副本。假如类B 从A1和A2两个类多重继承而来,这样B类就包含A1、A2类的数据成员副本。考虑如果A1、A2都从某...
  • 问题描述 ...这样一个子类继承多个父类的问题是多继承问题,如果父类之间有同名的方法或者属性,就会产生二义性。 继承多份父类的属性,超成资源的浪费 同名属性,产生二义性 #include "iostr...
  • 【C++】c++继承

    2017-04-05 11:08:26
    我们都知道继承性在客观世界是一种常见的现象。在我们了解C++的继承之前,让我们先介绍一个现实世界“动物”的例子,它们之间的属性继承关系如图所示: 从面向对象的观点来看,继承所表达的正是这样一种类与...
  • 对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就需要对当前类和基类进行搜索以确定方法所在的位置。而搜索的顺序就是所谓的「方法解析顺序」(Method ...
  • has-A:包含关系,用以描述一个类由个“部件类”构成。实现has-A关系用成员表示,即一个类的数据成员是另一种已经定义的类。 uses-A:一个类部分地使用另一个类。通过类之间成员函数的相互联系,定义友元或对象...
  • 什么是继承? 继承的工作方式 继承与转换 派生类的构造 单继承 & 多继承 菱形继承
  • C++中继承及virtual小结

    千次阅读 2018-04-04 18:01:17
    一、继承基础知识C++继承1.1继承的基本概念类与类之间的关系has-A,包含关系,用以描述一个类由个“部件类”构成,实现has-A关系用类的成员属性表示,即一个类的成员属性是另一个已经定义好的类。use-A,一个...
  • C++如何使类不能继承 [转]

    千次阅读 2012-06-28 12:06:59
    在使用了多继承的类层次这也是防止出现菱形继承层次结构的一个好办法. 要实现一个不能被继承的类有很多方法.   主要的思路就是使子类不能构造父类的部分,这样子类就没有办法实例化整个子类.这样就限制了子类...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,839
精华内容 11,135
关键字:

关于多继承二义性的描述中