C++中的继承——第二篇

一、继承与友元

友元关系不能够继承(就像父亲的朋友不一定是自己的朋友)

具体实现起来就是父类的友元可以访问父类的成员,但是不可以访问子类的成员

二、继承与静态成员

子类的静态成员变量本质上与父类的是同一份,存储在静态区中,所以可以继承

例如

class Person
{
public:
    static int _count = 0
}

可以直接继承到子类

三、单继承与多继承

3.1单继承是什么?

一个子类只有一个直接父类,如:

class Student : public Person
{}

3.2多继承

3.2.1定义

一个子类有两个及以上的直接父类,如:

class Assistant : public Student,public Teacher
{}

3.2.2菱形继承中的数据冗余和二义性

用例子来说明:

如图,Student与Teacher都继承自Person,而Assistant又多继承了Student与Teacher,那么这时候Student与Teacher中属于Person的那一部分就会出现冗余,我们称之为数据冗余

当我们运行下面一段代码的时候

Assistant a;
a._name;

此时我们会发现在Assistant中有两份_name,一份属于Student,一份属于Teacher,因此运行时会因为不知访问那个而报错,我们称之为二义性

3.2.3virtual:虚继承

按照之前分析,我们已经知道了数据冗余和二义性的存在,那么应该如何解决它呢?

为此,我们引入了virtual关键字来完成虚继承的概念,虚继承后,我们可以得到如下图的存储方式:

使用虚继承的方法也很简单,只需要在继承共有父类的时候加上virtual关键字:

class Student: virtual public Person
{}
3.2.3补:复杂菱形继承时的位置

假如要完成如下图的复杂菱形继承

分析可知,在继承A的时候会出现数据冗余和二义性的问题,因此我们要在

A->B

A->C

这两个继承的时候使用virtual来修饰

3.3总结

在实际应用当中,我么并不推荐使用菱形继承,因为这会降低代码可读性(虽然iostream就是菱形继承),但是使用多继承是完全没问题的

四、继承和组合

4.1两者的本质都是:复用

4.1补:黑盒测试和白盒测试的概念

白盒测试:可见底层代码的实现,是对代码功能的实现过程进行测试,对技术要求高

黑盒测试:不可见代码的底层实现,直接对代码的功能进行测试,对技术要求低

4.2is-a关系与has-a关系(特指类之间的关系)

public继承是一种is-a关系,就是说每个派生类对象都是一个基类对象

组合是一种has-a关系,假设B组合了A,每个B对象中都有一个A对象,例如我们在vector类模板中在成员变量列表使用了迭代器类来作为成员变量

4.2补:在程序设计中,我们推荐“高内聚,低耦合”的代码形式

其中低耦合特指两个类之间关系,我们希望类与类之间关系不要太紧密。

4.3组合的好处

组合的原则是在类中少放公用,大多在保护中实现,仅仅向外展示功能接口,因此组合十分符合低耦合的形式

4.4继承与组合的对比

①继承允许根据基类的实现来定义派生类的实现,这种以生成派生类为目的的复用,我们称为白箱复用,但是因为白箱可视度高,所以基类的改变对派生类影响很大,耦合度比较高

②对象组合是继承之外的另一种复用方式,class Person中定义保护成员hand h1;

而hand是另外实现的一个类,这时两个类之间体现出了对象组合

在这个例子中,我们称hand类被Person类组合了,被组合的对象通常需要有良好的接口,这种复用风格成为黑箱复用,因为对象内部不可见,耦合度低

4.5is-a与has-a关系的应用场景

has-a关系时用对象组合,例如人体和手

is-a关系时用继承,例如植物和水果

当has-a与is-a都符合的时候,用组合,如list与queue

上一篇:免费无广,这5款才是真正的Windows必装软件,一个比一个好用


下一篇:C语言strtol函数使用的坑