C++_代码重用4-多重继承
继承使用时要注意,默认是私有派生。所以要公有派生时必须记得加关键字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-多重继承的更多相关文章
- C++_代码重用1-总览
C++的主要目的是促进代码重用. 公有继承是实现这一目标的机制之一: 本身是另一个类的成员,这种方法称为包含.组合.层次化. 另一种方法是使用私有.保护继承. 通常包含.私有继承和保护继承用于实现ha ...
- C++_代码重用5-类模板
如果两种类只是数据类型不同,而其他代码是相同的,与其编写新的类声明,不如编写一种泛型(独立于类型的)栈.然后将具体的类型作为参数传递给这个类.这样就可以使用通用的代码生成存储不同类型值的栈. 可以使用 ...
- C++_代码重用3-私有继承
使用包含:易于理解,类声明中包含表示被包含类的显式命名对象,代码可以通过名称引用这些对象: 使用继承:将使关系更抽象,且继承会引起很多问题,尤其是从多个基类继承时. 私有继承所提供的特性确实比包含多. ...
- C++_代码重用2-包含对象成员的类
对于姓名可以使用字符数组来表示,但这将限制姓名的长度.当然,还可以使用char指针和动态内存分配,但这要求提供大量的支持代码.有一个好的方法就是使用一个他人开发好的类的对象来表示.如果C++库提供了合 ...
- Javascript中的Trait与代码重用
Javascript中的Trait与代码重用 来源 http://www.ituring.com.cn/article/64103 我们知道,OOP中最普遍的代码重用方式是通过继承,但是,继承有一些缺 ...
- 《C++ Primer Plus》读书笔记之十二—C++中的代码重用
第14章 C++中的代码重用 1.C++代码重用方法:公有继承.使用本身是另一个类的对象的类成员(这种方法称为包含.组合或层次化).私有或保护继承.类模板等. 2.模板特性意味着声明对象时,必须指定具 ...
- C++ primer plus读书笔记——第14章 C++中的代码重用
第14章 C++中的代码重用 1. 使用公有继承时,类可以继承接口,可能还有实现(基类的纯虚函数提供接口,但不提供实现).获得接口是is-a关系的组成部分.而使用组合,类可以获得实现,但不能获得接口. ...
- “前.NET Core时代”如何实现跨平台代码重用 ——程序集重用
除了在源代码层面实现共享("前.NET Core时代"如何实现跨平台代码重用 --源文件重用)之外,我们还可以跨平台共享同一个程序集,这种独立于具体平台的"中性" ...
- PHP代码重用与函数编写
代码重用与函数编写 1.使用require()和include()函数 这两个函数的作用是将一个文件爱你载入到PHP脚本中,这样就可以直接调用这个文件中的方法.require()和include()几 ...
随机推荐
- JDK的安装和环境配置
安装环境:网上下载的JDK一般都包含JRE在里面,安装JDK完成后会提示接着装JRE,如果没提示再去下载另装如:jdk_8u101_windows_x64_8.0.1010.13 配置环境:新建系统变 ...
- Memcached 原理
memcached 是以一个守护进程的方式运行于一个服务器和多个服务器之间的,等待接受客户端的连接操作,客户端可以有各种语言编写.(例如PHP). php 在客户端与服务器建立连接以后,接下来的事情 ...
- 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/ ...
- django获取字段列表(values/values_list/flat)
django获取字段列表(values/values_list/flat) values方法可以获取number字段的字典列表 values_list可以获取number的元组列表 values_li ...
- mvc json 日期问题的最简单解决方法
1.首先编写BaseController这个类,需要引入Newtonsoft.Json.dll程序集 using System;using System.Collections.Generic;usi ...
- vis用于做3D图表的js插件
vis.js用于做3D图表:(浏览网站需要FQ)实例:http://visjs.org/graph3d_examples.html代码下载:https://github.com/almende/vis
- 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 ...
- 【2008nmj】GDA二元分类.docx
- 编写高质量代码改善C#程序的157个建议——建议34:为泛型参数设定约束
建议34:为泛型参数设定约束 “约束”这个词可能会引起歧义,有些人肯能认为对泛型参数设定约束是限制参数的使用,实际情况正好相反.没有“约束”的泛型参数作用很有限,倒是“约束”让泛型参数具有了更多的行为 ...
- CentOS Vi编辑器
vim:通过vim a.cfg进入文档 i:编辑状态 ESC:返回不可编辑状态 dd:在不可编辑状态下,dd可删除光标所在的行,2dd删除两行,以此类推 u:在不可编辑状态下,u可恢复删除的行 yy: ...