C++多继承中的二义性问题

article/2025/10/14 19:48:13
    在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;
}

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









http://chatgpt.dhexx.cn/article/GP71Q6di.shtml

相关文章

二义性文法和无二义性文法

二义性文法是指一种产生式规则可以被解释成两种或更多种不同的语法结构的文法。这种文法会导致语言的歧义和不确定性&#xff0c;使得相同的语句可以有不同的解释。 以下是三个例子&#xff1a; S → aSb | ε 这个文法可以生成字符串"aaabbb"&#xff0c;但是它有两…

如何消除文法的二义性

文法举例 显然&#xff0c;对于not p and q有两种推导方式 默认not优先级高于and,即(not p) and q 默认and优先级高于 not,即not(p and q) 先and再not先not再and 两种消除二义性的方法 简单来说&#xff0c;就是人为规定not\and\or的优先级即可 重写的文法相当于默…

C++多继承中二义性的解决方案

出现二义性的原因&#xff1a; 派生类在访问基类成员函数时&#xff0c;由于基类存在同名的成员函数&#xff0c;导致无法确定访问的是哪个基类的成员函数&#xff0c;因此出现了二义性错误。 1. 什么是多重继承的二义性 class A{ public:void f(); }class B{ public:void f(…

编译原理——证明文法的二义性(1)

目录 推导和语法树推导语法树 文法二义性 在证明文法的二义性之前&#xff0c;我们需要熟悉几个基本的概念。 推导和语法树 推导 这里的推导&#xff0c;简单的来说就是指根据给出的句型&#xff08;句子&#xff09;&#xff0c;对文法进行推理变化最终得到句型&#xff08…

二义性

自然语言的二义性什么意思 面这个问题.很清楚的说明了自然语言的二义性.. 用红墨水写一个“蓝”字&#xff0c;请问&#xff0c;这个字是红字还是蓝字&#xff1f; 可能很少有人意识到&#xff0c;像红字和蓝字这样的词语都存在着二义性。可能是红色的字&#xff0c;也可能是“…

2.5.2 文法的二义性

2.5.2 文法的二义性 设有文法 G [ E ]: E → E E | E * E | ( E ) | i句子 i * i i 有两个不同的最左推导,对应两棵不同的语法树,见图 2.6 和图 2.7 。 最左推导 1 E ⇒ E E ⇒ E * E E ⇒ i * E E⇒ i * i E⇒ i * i i 最左推导 2 E ⇒ E * E ⇒ i * E⇒ i * E E⇒…

编译原理(三)语法分析:3.二义性与二义性的消除

文章目录 一、二义性1.定义2.原因 二、二义性的消除1.改写二义文法为非二义文法&#xff08;1&#xff09;步骤&#xff08;2&#xff09;例子&#xff08;3&#xff09;缺点 2.为文法符号规定优先级和结合性3.修改语言的语法&#xff08;表现形式被改变&#xff09; 【编译原理…

二义性和C++消除二义性

1.二义性 二义性的定义是&#xff1a;“如果文法G中的某个句子存在不只一棵语法树&#xff0c;则称该句子是二义性的。如果文法含有二义性的句子&#xff0c;则称该文法是二义性的。”&#xff08;该定义来自于百度百科&#xff09;用通俗的话讲&#xff0c;如果一句话或者一个…

C++ 二义性是什么?怎么解决?

一、什么是二义性 在多继承的场景里&#xff0c;当父类中存在同名变量时&#xff0c;子类访问父类的同名变量&#xff0c;将出现二义性&#xff0c;因为编译器不知道你将要访问的是哪个父类中的变量。 举个例子&#xff1a; class A { public:int a; // B1&#xff0c;B2 都…

ES6一维数组去重,合并去重方法分享

ES6去重的几个小方法 1.使用set方法 2.setArray.from() 3.filtermap 4、Array.fromsetflatsort 排序去重 flat:对数组进行扁平化处理 sort:排序 b-a:倒序 a-b:正序 5.数组合并去重

[记录]es6常用去重方法(数组、字符串)

数组去重 ES6 ES6以下方法除了代码简洁外,对于undefined和NaN也同样可以达到去重的效果 new Set()是ES6新增的数据结构,类似于数组,但它的一大特性就是所有元素都是唯一的,没有重复的值,我们一般称为集合,Set本身是一个构造函数,用来生成 Set 数据结构。 Set搭配扩展运算符 ……

JavaScript数组去重—ES6的两种方式

说明 JavaScript数组去重这个问题&#xff0c;经常出现在面试题中&#xff0c;以前也写过一篇数组去重的文章&#xff0c;&#xff08;JavaScript 数组去重的多种方法原理详解&#xff09;但感觉代码还是有点不够简单&#xff0c;今天和大家再说两种方法&#xff0c;代码可是足…

ES6 Set() 数组去重

ES6 Set()去重 Set。它类似于数组&#xff0c;但是成员的值都是唯一的 通过add()方法向 Set 结构加入成员 let arr [1,2,3,4,1,5,2,3]; var set2 new Set(); arr.forEach(item>{set2.add(item) }) console.log(set2); console.log(Array.from(set2));let str [测试1,测试…

ES6数组去重的三个简单办法

ES6数组去重的三个简单办法 简单说一下利用ES6实现数组去重的三个办法。 第一种: 利用Map对象和数组的filter方法 贴上相关代码 打印后的结果 通过打印我们发现&#xff0c;确实实现了我们想要的效果。那么下面简单来解释一下。 1.Map对象是ES6提供的一个新的数据结构&…

一文弄懂Python中的*args 和 **kwargs

1. 引言 在本文中&#xff0c;我们将讨论 Python 中的 *args 和 **kwargs 及其用法和示例。 闲话少说&#xff0c;我们直接开始吧。 2. 问题引入 在Python中写函数的时候&#xff0c;我们经常需要给函数传值&#xff0c;这些值被称为函数参数。 我们不妨来举个栗子&#xff…

**kwargs python_python中**kwargs怎么用?

1、使用两个星号是收集关键字参数&#xff0c;可以将参数收集到一个字典中&#xff0c;参数的名字是字典的 “键”&#xff0c;对应的参数的值是字典的 “值”。请看下面的例子&#xff1a;>>> def print_kwargs(**kwargs): ... print(kwargs) ... >>> pr…

Python技巧:​args 和 kwargs 原来这么强大

大家好&#xff0c;今天我给大家分享Python技巧&#xff1a;​args 和 kwargs的相关技巧。喜欢记得收藏、关注、点赞。 注&#xff1a;完整代码、资料、技术交流文末获取 现在args和 kwargs参数仍然是 Python 中非常有用的特性&#xff0c;而且理解它们的威力将使您成为更有效…

*args和**kwargs是什么意思

去面试的时候&#xff0c;做了一道笔试题——什么是*args和**kwargs&#xff0c;区别在哪里&#xff1f; 有点蒙&#xff0c;好像见过&#xff0c;但是不知道具体的意思。所以回来查了一下资料&#xff0c;做一下笔记。 总的来说&#xff0c;*args代表任何多个无名参数&#x…

埃及分数c语言设计,埃及分数(四)

最优分解 源程序 下面就是求埃及分数最优分解的 C 语言源程序 EgyptianFraction.c&#xff1a; 1: #include 2: #include 3: #include 4: 5: const int SIZE 64; 6: static int wp -1, bp -1; 7: static mpz_t z, w, work[SIZE], best[SIZE]; 8: static mpq_t q1, q2; 9:…

埃及分数问题

问题描述: 古埃及人喜欢用最少的分子为 1 的真分数来表示一个真分数&#xff0c;比如7 / 8 1 / 2 1 / 3 1 / 24 。设计程序把一个真分数表示为最少的埃及分数之和的形式。 思路&#xff1a; 首先要知道什么是真分数&#xff1a;真分数是指大于0小于1的所有分数。这些分数的特…