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()几 ...
随机推荐
- libevent源码深度剖析八
libevent源码深度剖析八 ——集成信号处理 张亮 现在我们已经了解了libevent的基本框架:事件管理框架和事件主循环.上节提到了libevent中I/O事件和Signal以及Timer事件的 ...
- Oracle设置主键自增长
第一步:为表设置主键 第二步:新建序列 CREATE SEQUENCE SQ.SEQ_INCREASE START WITH 12 MAXVALUE 999 MINVALUE 0 INCREME ...
- Mysql处理海量数据时的一些优化查询速度方法(转)
最近一段时间由于工作需要,开始关注针对Mysql数据库的select查询语句的相关优化方法. 由于在参与的实际项目中发现当mysql表的数据量达到百万级时,普通SQL查询效率呈直线下降,而且如果whe ...
- 卡2-SLAM
---恢复内容开始--- 1.下载 首先需要从github上Git以下两个包: git clonehttps://github.com/ros-perception/open_karto(开源的kar ...
- 通过网页发布ios应用。
原文地址:http://www.zhihu.com/question/24304345 两种方法: 1. 测试版本 支持任何类型的开发者帐号,需要在developer后台设置授权deviceID,可以 ...
- JavaScript 组件编写
说明 这是一个联系人名过滤组件,还提供可选的"大小写是否敏感"选项,默认大小写不敏感. 一.HTML 结构 <ul class="contacts"> ...
- javascript总结7:算术运算符
1 运算符: 加号+ 如果是数字类型的变量相加,那么结果为数字类型; 如果是非数字类型的变量相加,结果为字符串类型 2 减号- 如果是非数字类型的变量相减结果为 NaN 3 乘号 * 如果是非数 ...
- Build fat static library (device + simulator) using Xcode and SDK 4+
155down votefavorite 185 It appears that we can - theoretically - build a single static library that ...
- 设计模式05: Prototype 原型模式(创建型模式)
Prototype 原型模式(创建型模式) 依赖关系的倒置抽象不应该依赖于实现细节,细节应该依赖于抽象.对所有的设计模式都是这样的. -抽象A直接依赖于实现细节b -抽象A依赖于抽象B,实现细节b依赖 ...
- jquery中attr和prop的区别(转)
在高版本的jquery引入prop方法后,什么时候该用prop?什么时候用attr?它们两个之间有什么区别?这些问题就出现了. 关于它们两个的区别,网上的答案很多.这里谈谈我的心得,我的心得很简单: ...