--------------------------------一、“倒三角”二义性问题-------------------------------

问题描述:卤煮之所以称之为“倒三角问题”,是因为这一类二义性问题所处的继承体系类似于倒三角形状,如图:

这样,在子类中就存在父类A、B的两份show(),在调用的时候就会出现二义性问题,这种问题该怎么解决呢?

面对问题:
//下面这种情况出现的二义性怎么解决?
/*
class grandpa
{
public:
    void show()
    {
        cout<<"This is grandpa\n";
    }
};
class father
{
public:
    void show()
    {
        cout<<"This is father\n";
    }
};
class son:virtual public grandpa,virtual public father
{
public:
    void display()
    {
        cout<<"This is son\n";
    }
};
int main()
{
    son son;
    son.show();
    son.display();
    cout << "Hello world!" << endl;
    return 0;
}
//这里的“倒三角”问题二义性怎么解决?即有两个基类共同派生出一个子类,这两个基类中又同时存在相同的功能的时候
//派生出的子类在调用该功能的时候也会出现二义性问题  这时候该怎么解决?
//解决方法:利用区域限定符(::)  详细解决方案见实验tempt
*/
 
解决方法:区域限定符(::)
#include <iostream>

using namespace std;
//下面这种情况出现的二义性怎么解决?
class grandpa
{
public:
    void show()
    {
        cout<<"This is grandpa\n";
    }
};
class father
{
public:
    void show()
    {
        cout<<"This is father\n";
    }
};
class son:virtual public grandpa,virtual public father
{
public:
    void display()
    {
        cout<<"This is son\n";
    }
};
int main()
{
    son son;
    son.father::show();//“倒三角”问题出现的二义性利用区域限定符(::)来解决
    son.grandpa::show();
    son.display();
    return 0;

}
-------------------------------------------二、“恐怖菱形”二义性问题---------------------------------------
面对问题:
描述:有最基类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,就导致了二义性。

 图示:
 

解决方案:  虚基类、虚继承
教科书上面对C++虚基类的描述玄而又玄,名曰“共享继承”,名曰“各派生类的对象共享基类的的一个拷贝”,其实说白了就是解决多重多级继承造成的二义性问题。例如有基类B,从B派生出C和D,然后类F又同时继承了C和D,现在类F的一个对象里面包含了两个基类B的对象,如果F访问自己的从基类B那里继承过来的的数据成员或者函数成员那么编译器就不知道你指的到底是从C那里继承过来的B对象呢还是从D那里继承过来的B对象。

 

于是虚基类诞生了,将C和D的继承方式改为虚继承,那么F访问自己从B那里继承过来的成员就不会有二义性问题了,也就是将F对象里的B对象统一为一个,只有一个基类B对象,下面是一段代码说明了对虚基类的使用。

 
 

#include <iostream>

 
 

using namespace std;

 
 

class A
{
    public:
    int i;
    void showa(){cout<<"i="<<i<<endl;}
};

 
 

class B:virtual public A      //此处采用虚继承
{
    public:
    int j;
};

 
 

class C:virtual public A      //此处采用虚继承
{
    public:
    int k;
};

 
 

class D:public B,public C
{
    public:
    int m;
};
int main()
{
    A a;
    B b;
    C c;
    a.i=1;
    a.showa();
    b.i=2;
    b.showa();
    c.i=3;
    c.showa();
    D d;
    d.i=4;
    d.showa();
    //cout << "Hello world!" << endl;
    return 0;
}

 
 

从这个代码我们可以看出B,C,D从A那里继承过来了i这个变量并且它们之间不会有任何影响,如果B和C不是虚继承方式的,那么d.i=4;就不能编译通过了。

C++中常见的两种二义性问题及其解决方式的更多相关文章

  1. MathType中常见的两种符号的运用

    想要让公式编辑得快速又高效,MathType数学公式编辑器这个神助攻是少不了的.MathType是一款专用的数学公式编辑器,用它来编辑公式非常方便实用,并且排版也非常简单.下面介绍两种常见符号的应用. ...

  2. python接口测试中常见的两种接口依赖处理方式

    一.请求体的字段依赖 这种情况多数是在当前测试的接口,它的前置接口的请求体中的字段要拿来在当前的接口请求体中继续使用,比如修改用户信息的接口,该接口会使用到用户名的字段,该字段是由创建用户时的请求体中 ...

  3. Java 获取*.properties配置文件中的内容 ,常见的两种方法

    import java.io.InputStream; import java.util.Enumeration; import java.util.List; import java.util.Pr ...

  4. Java中常见的5种WEB服务器介绍

    这篇文章主要介绍了Java中常见的5种WEB服务器介绍,它们分别是Tomcat.Resin.JBoss.WebSphere.WebLogic,需要的朋友可以参考下 Web服务器是运行及发布Web应用的 ...

  5. CAN总线常见的两种编码格式(Intel/Motorola)

    在汽车电子行业的开发或者测试中,我们经常会看到CAN总线信号的常见的两种编码格式:Intel格式与Motorola格式. 讲解这两种格式之前,我们先来了解一些大端模式和小端模式,会对后面理解这两种编码 ...

  6. SpringBoot读取.yml配置文件最常见的两种方式-源码及其在nacos的应用

    一.前言 我们在开发中会经常遇到一些可能会变的值,比如数据库的密码,一些关键链接的配置等等. 都需要我们写在配置文件中,这样可以把这些配置文件放到nacos上进行管理,修改nacos的配置,咱们发布的 ...

  7. java中线程分两种,守护线程和用户线程。

    java中线程分为两种类型:用户线程和守护线程. 通过Thread.setDaemon(false)设置为用户线程: 通过Thread.setDaemon(true)设置为守护线程. 如果不设置次属性 ...

  8. ORACLE中常见的几种锁

    ORACLE中常见的几种锁: 0:none 1:null 空 2:Row-S 行共享(RS):共享表锁,sub share 3:Row-X 行独占(RX):用于行的修改,sub exclusive 4 ...

  9. AspNetWebApi管线中如果定义两种类型的消息处理程序(全局/路由)

    AspNetWebApi管线中如果定义两种类型的消息处理程序(全局/路由) 在AspNetWebApi管线中存在两种类型的消息处理程序(Message Handler) 1.全局消息处理程序,所有的请 ...

随机推荐

  1. .Net Core Linux centos7行—.net core json 配置文件

    .net core 对配置系统做出了大幅度更新,不在局限于之前的*.xml配置方式.现在支持json,xml,ini,in memory,环境变量等等.毫无疑问的是,现在的json配置文件是.net ...

  2. url 中 # ? & 的作用

    1. # 10年9月,twitter改版.一个显著变化,就是URL加入了"#!"符号.比如,改版前的用户主页网址为http://twitter.com/username改版后,就变 ...

  3. 如何让tableViewCell的分割线从边框顶端开始

    在ios8上 [TableView setSeparatorInset:UIEdgeInsetsMake(0,0,0,0)];不起作用 经过测试加入下面方法 在ios7 8上都可以正常工作 -(voi ...

  4. Jsoup 使用教程:数据抽取

    1.使用DOM方法来遍历一个文档 问题 你有一个HTML文档要从中提取数据,并了解这个HTML文档的结构. 方法 将HTML解析成一个Document之后,就可以使用类似于DOM的方法进行操作.示例代 ...

  5. cocos2d-x 3.10 PageView BUG

    cocos2d-x 3.10 PageView 拖动滚动到下一个单元,没事件,3.11有修复.

  6. Finite State Machine 是什么?

    状态机(Finite State Machine):状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动       作.完成特定操作的控制中心. 类 ...

  7. angularjs中ckeditor的destroy问题

    项目中,在切换了页面的tab页后会发现上传图片的操作报错,检查后发现问题根源是切换了tab页重新加载页面时ckeditor又会创建一次,这个时候的ckeditor已经不是第一次创建的那个了,所以上传图 ...

  8. Phylab2.0 文档汇总

    实验数据处理脚脚本 编写规范 调用框架以及测试文件规范 脚本调用约定 API文档 用户部分后端请求说明 文章评论区部分后端请求说明 测试报告 测试报告集

  9. 在github上搭建hexo博客

    准备工作 安装git 系统是win10家庭版,采用git v1.9.5版本,比较简单,一路next直到finsh完成安装. 安装node.js hexo是基于node.js驱动的一款快速.简单且功能强 ...

  10. linux系统下修改文件夹目录权限

    linux系统下修改文件夹目录权限 文件夹权限问题 Linux.Fedora.Ubuntu修改文件.文件夹权限的方法差不多.很多人开始接触Linux时都很头痛Linux的文件权限问题.这里告诉大家如何 ...