c++继承总结

来源:互联网 发布:2017色情交友软件 编辑:程序博客网 时间:2024/05/21 14:04

is-a

public继承,是一种D是B的一种,但B不一定都是D。

在这种继承关系下,通常意义上的理解,会在程序中出现乱流。例如,企鹅是一种鸟,又鸟派生出的企鹅,却不能飞。

因此,在鸟中派生出会飞的鸟,再派生出企鹅会更好。即,采用双继承区分。

即使如此,此刻我们仍然未能完全处理好这些鸟事,因为对某些软件系统而言,可能不需要区分会飞的鸟和不会飞的鸟。如果你的程序忙着处理鸟啄和鸟翅,完全不在乎飞行,原先的"双classes 继承体系"或许就相当令人满足了。这反映出一个事实,世界上并不存在一个"适用于所有软件"的完美设计。所谓最佳设计,取决于系统希望做什么事,包括现在与未来。如果你的程序对飞行一无所知,而且也不打算未来对飞行"有所知",那么不去区分会飞的鸟和不会飞的鸟,不失为一个完美而有效的设计。实际上它可能比"对两者做出区隔"更受欢迎,因为这样的区隔在你企图塑模的世界中并不存在。

还有一种思想,就是让企鹅继承鸟,但是,在企鹅的飞行函数中,提出错误,不能飞!这是运行期错误。

或者,不定义飞行函数,那么对于企鹅飞行的调用,在编译期,就会报错。

两者不同,但是,好的接口,防止无效的代码通过编译。所以。。。

复合:某种类型中含有其他类型。has-a)或is-implemented-in也rms-of 根据某物实现出

这两种关系分别用于不同的领域

当复合发生在程序中的对象属于的应用领域。此时,就是has-a关系。

当复合发生在缓冲区,互斥器,查找树等相当于软件的实现域时,就是根据某物实现。

要注意区分is-a与根据某物实现的区别。

Private 继承意味implemented-in-terms-of根据某物实现出

pnvate 继承意味只有实现部分被继承,接口部分应略去。

它跟复合,一样,该如何取舍呢,

尽量用复合,必要是采用私有继承。何时才是必要?主要是当protected 成员和虚 函数牵扯进来的时候。其实还有一种激进情况,那是当空间方面的利害关系足以踢翻private 继承的支柱时。

采用私有继承,可以免除程序在继承后,继承到的基类函数,变成接口的混乱感觉。

也可以用复合代替私有继承,我们在类中声明一个私有的嵌套类。该类以共有形式继承需要继承的类。然后,在原类中,申明一个嵌套类私有对象。

两种方式:

第一种,当原类有派生类时,无法阻止重新定义虚函数。但第二种方法却可以。因为,原类的派生类。无法取得私有的嵌套对象。因为,无法继承,或者重新定义虚函数,类似于Jave中的(final)。c#中的sealed。

同时,第二种方法,更加优化了编译依存性。

private 继承主要用于当一个意欲成为derived class 者想访问一个意欲成为base class 者的protected 成分,或为了重新定义一或多个virtual 函数
但这时候两个classes 之间的概念关系其实是is-implemented-in-terms-of (根据某物实现出)而非is-a。然而我也说过,有一种激进情况涉及空间最优化,可能会促使
你选择"private 继承"而不是"继承加复合"。

 

关于派生方式下的隐藏规则:

公有继承下:

根据C++名称遮掩规则,派生类和基类有相同名字的函数,成员变量,都会发生隐藏。不管函数是否为虚函数,不管参数是否相同,派生的同名函数,都会隐藏基类的同名函数。解决方式:用using base:fun;让基类同名函数,在派生类可见。

 私有继承下:

由于继承方式为私有。因为,using 方式会让继承而来的某给定名称的所有同名函数,在派生类,都可见。于是,此时,采用inline的转交函数。即,在派生类同名函数中,采用base:fun();方式、

 

区分接口继承和实现继承

对于类的继承,通常有两部分组成,一部分是接口,一部分是实现。

纯虚函数的目的,是为了让派生类只继承函数接口。但是,可以给纯虚函数一个定义代码,在调用的时候,指定类名称。

即:纯虚函数的申明是对派生类说。你必须提供该函数,但我不干涉你怎么实现。

虚函数目的是为了让派生类继承类的接口和缺省实现。

即:基类对派生类说。你必须提供该函数,但如果你不想自己实现,可以用我的默认实现、

但这有可能造成危险,在新添加一个类的时候,没有要求说明要缺省实现该函数而直接继承缺省行为。因此,造成灾难。

可行之法是。我们讲虚函数,改为纯虚函数,同时,添加一个普通函数实现缺省行为,让派生类在虚函数中,inline调用该缺省普通函数。注意,该默认普通函数,应该设计为protected

有些人反对用以不同的函数,分别提供接口和缺省实现。于是,采用纯虚函数在派生类中重新声明的方式,同时让它们拥有自己的实现。此时,纯虚函数在基类有自己的定义,也是public的。派生类在各自类中,重写自己的实现。也可以是用基类的缺省行为。

普通函数:

目的是为了令派生类继承接口以及一份强制实现、

千万记住:绝对不要重新定义继承而来的非虚函数。因为这会和public继承的is-a关系,以及类中的不变性,凌驾其特异性发生矛盾。

同时,千万不要重新定义继承而来的虚函数的缺省参数值。因为缺省参数值是静态绑定的,而虚函数,是动态绑定的。

假设调用一个派生类的虚函数的同时,又在使用基类为它设定的缺省参数值,导致该函数调用有个奇怪的组合,基类和派生类的申明各占一半。

C++之所以有虚函数的缺省值,是为了效率,在运行期,决定虚函数的缺省参数,提前到编译期。

 

 关于空类问题

所谓空类,就是说,不带任何数据,这样的类没有非静态成员变量,没有虚函数,也没有虚基类,因此,这样的空类对象,不使用任何空间,因为没有任何隶属对象的数据需要存储,然而,由于技术上的理由,C++裁定独立(非附属)对象必须有非零大小,在大多数编译器中,这样的空类大小为1.因为,面对这样的对象,C++官方,通常安插一个char,同时,由于字节对齐问题,可能大于1.需要注意的是,这里,必须是独立,非附属对象。也就是说,这个约束,不适合于派生类对象的基类成分  。例如EBO(空白基类优化)。即,你的类,私有继承一个空类。此时,大小为真正的类大小。但是,EBO只适合于单一继承。

原创粉丝点击