继承使用时要注意,默认是私有派生。所以要公有派生时必须记得加关键字Public。

MI(Multi Inheritance)会带来哪些问题?以及如何解决它们?

两个主要问题:

从两个不同的基类继承同名方法;

从两个或更多相关基类那里继承同一个类的多个实例;

虚方法

Worker公有派生出Singer和Waiter;

然后Singer和Waiter公有派生出SingingWaiter(即多重继承);

这样会导致一个问题,就是SingingWaiter中有两个Worker组件。通常可以将派生类对象的地址赋值给基类指针。但是在这样的情况下这么做的话,将出现二义性。所以必须使用类型转换来指定对象。但这又增加了指针引用的复杂度。

C++在引入多重继承的同时,也引入新技术——虚基类,来解决该问题。

虚基类也用关键字virtual,虚基类与虚函数之间并不存在明显的联系。这么做是为了给程序员减少压力,类似于关键字的重载。

class Singer: virtual public Worker{…};

class Waiter: public virtual Worker{…};

(virtual和public的次序无关紧要)

那么为什么不使虚行为成为MI的默认准则呢?

在一些情况下,可能需要基类的多个拷贝;

将基类作为虚的要求程序完成额外的计算,为不需要的程序付出代价是不应当的;

新的构造函数规则

使用虚基类时,必须对构造函数采用新的方法;

对于非虚基类,唯一可以出现在初始化列表中的构造函数是即时基类构造函数。

A派生B,B派生C;--->C类的构造函数只能调用B类的构造函数,B类的构造函数只能调用A类构造函数。

但对于虚基类而言,这种信息自动传递方式不可用。这是因为对于多重继承而言,信息传递将通过两条不同的途径。为避免这种冲突,当基类是虚的,将禁止信息通过中间类自动传递给基类。

这就要求显式地调用所需的基类构造函数:

SingingWaiter(参数列表):Worker(wk),Waiter(wk,p),Singer(wk,v) { }

上述格式对虚基类来说是合法的,对非虚基类来说是非法的。

哪个方法

对于多重继承,如果每个祖先都有一个Show函数,那么会导致函数调用的二义性

对于单继承,如果没有重新定义show,将调用最近祖先中的show定义。

有几种解决方法:

1使用作用域解析运算符来澄清编程者的意图;

2或是在多重继承的类中重新定义show方法,并指出要使用哪个show;

这种递增的方法对于单继承来说是有效的;

但是对于多重继承来说,还是有问题:

SingingWaiter::Show

{Singer::Show();Waiter::Show();} //这将显示姓名和ID两次。

该如何解决呢?->使用模块化方法,而不是递增的方法;即提供一个只显示worker组件的方法,提供一个只显示waiter组件及singer组件的方法。

将所有数据组件都设置为保护的方法,而不是私有的,可以更严格地控制对数据的访问;

如果数据组件的方法是保护的,则只能在继承层次结构中的类中使用它,在其他地方则不能使用。

MI小结

MI会增加编程的复杂度。然而,这种复杂度主要是由于派生类通过多条途径继承同一个基类引起的。

当派生类使用关键字virtual来指示派生时,基类就称为了虚基类。其构造函数的规则有所变化,不会自动进行信息不换传递,需要显式地调用基类构造函数。

通过优先规则解决名称二义性。如果一个类从两个不同的类那里继承了两个同名的成员,则需要在派生类中使用类限定符来区分它们。否则,编译器将指出二义性。

有间接虚基类的派生类包含直接调用间接基类构造函数的构造函数,这对于间接非虚基类来说是非法的。

C++_代码重用4-多重继承的更多相关文章

  1. C++_代码重用1-总览

    C++的主要目的是促进代码重用. 公有继承是实现这一目标的机制之一: 本身是另一个类的成员,这种方法称为包含.组合.层次化. 另一种方法是使用私有.保护继承. 通常包含.私有继承和保护继承用于实现ha ...

  2. C++_代码重用5-类模板

    如果两种类只是数据类型不同,而其他代码是相同的,与其编写新的类声明,不如编写一种泛型(独立于类型的)栈.然后将具体的类型作为参数传递给这个类.这样就可以使用通用的代码生成存储不同类型值的栈. 可以使用 ...

  3. C++_代码重用3-私有继承

    使用包含:易于理解,类声明中包含表示被包含类的显式命名对象,代码可以通过名称引用这些对象: 使用继承:将使关系更抽象,且继承会引起很多问题,尤其是从多个基类继承时. 私有继承所提供的特性确实比包含多. ...

  4. C++_代码重用2-包含对象成员的类

    对于姓名可以使用字符数组来表示,但这将限制姓名的长度.当然,还可以使用char指针和动态内存分配,但这要求提供大量的支持代码.有一个好的方法就是使用一个他人开发好的类的对象来表示.如果C++库提供了合 ...

  5. Javascript中的Trait与代码重用

    Javascript中的Trait与代码重用 来源 http://www.ituring.com.cn/article/64103 我们知道,OOP中最普遍的代码重用方式是通过继承,但是,继承有一些缺 ...

  6. 《C++ Primer Plus》读书笔记之十二—C++中的代码重用

    第14章 C++中的代码重用 1.C++代码重用方法:公有继承.使用本身是另一个类的对象的类成员(这种方法称为包含.组合或层次化).私有或保护继承.类模板等. 2.模板特性意味着声明对象时,必须指定具 ...

  7. C++ primer plus读书笔记——第14章 C++中的代码重用

    第14章 C++中的代码重用 1. 使用公有继承时,类可以继承接口,可能还有实现(基类的纯虚函数提供接口,但不提供实现).获得接口是is-a关系的组成部分.而使用组合,类可以获得实现,但不能获得接口. ...

  8. “前.NET Core时代”如何实现跨平台代码重用 ——程序集重用

    除了在源代码层面实现共享("前.NET Core时代"如何实现跨平台代码重用 --源文件重用)之外,我们还可以跨平台共享同一个程序集,这种独立于具体平台的"中性" ...

  9. PHP代码重用与函数编写

    代码重用与函数编写 1.使用require()和include()函数 这两个函数的作用是将一个文件爱你载入到PHP脚本中,这样就可以直接调用这个文件中的方法.require()和include()几 ...

随机推荐

  1. JDK的安装和环境配置

    安装环境:网上下载的JDK一般都包含JRE在里面,安装JDK完成后会提示接着装JRE,如果没提示再去下载另装如:jdk_8u101_windows_x64_8.0.1010.13 配置环境:新建系统变 ...

  2. Memcached 原理

    memcached  是以一个守护进程的方式运行于一个服务器和多个服务器之间的,等待接受客户端的连接操作,客户端可以有各种语言编写.(例如PHP). php 在客户端与服务器建立连接以后,接下来的事情 ...

  3. module 'keras.engine.topology' has no attribute 'load_weights_from_hdf5_group_by_name'

    参考: https://blog.csdn.net/heiheiya/article/details/81111932 https://blog.csdn.net/c20081052/article/ ...

  4. django获取字段列表(values/values_list/flat)

    django获取字段列表(values/values_list/flat) values方法可以获取number字段的字典列表 values_list可以获取number的元组列表 values_li ...

  5. mvc json 日期问题的最简单解决方法

    1.首先编写BaseController这个类,需要引入Newtonsoft.Json.dll程序集 using System;using System.Collections.Generic;usi ...

  6. vis用于做3D图表的js插件

    vis.js用于做3D图表:(浏览网站需要FQ)实例:http://visjs.org/graph3d_examples.html代码下载:https://github.com/almende/vis

  7. HTTP Modules versus ASP.NET MVC Action Filters

    from:http://odetocode.com/blogs/scott/archive/2011/01/17/http-modules-versus-asp-net-mvc-action-filt ...

  8. 【2008nmj】GDA二元分类.docx

  9. 编写高质量代码改善C#程序的157个建议——建议34:为泛型参数设定约束

    建议34:为泛型参数设定约束 “约束”这个词可能会引起歧义,有些人肯能认为对泛型参数设定约束是限制参数的使用,实际情况正好相反.没有“约束”的泛型参数作用很有限,倒是“约束”让泛型参数具有了更多的行为 ...

  10. CentOS Vi编辑器

    vim:通过vim a.cfg进入文档 i:编辑状态 ESC:返回不可编辑状态 dd:在不可编辑状态下,dd可删除光标所在的行,2dd删除两行,以此类推 u:在不可编辑状态下,u可恢复删除的行 yy: ...