基类的构造函数私有,派生类的构成必须调用基类的构造函数,但是基类的构成函数私有化以后,派生类看不见就不能调用了,那么派生类就无法实例化出对象。
运行一下——
这里必须调用基类的构造,但是基类这里是私有的,看不见,所以就不能再调用了。
C++11新增了一个final关键字,final修改基类,派生类就不能继承了。
我们同样运行一下——
在本文博主不展开讲,下篇博客,博主会介绍C++进阶中又一个重要的模块——【多态】,在【多态】中,博主会介绍两个涉及到【多态】中的重写相关知识点的关键字:override和final。
也就是说,final充当了两个作用——
(1)直接实现一个不能被继承的类(【继承】篇涉及知识点);(2)不让重写基类虚函数(【多态】篇即将涉及的知识点)。
友元关系不能继承。
这句话也就是说基类友元不能访问派生类私有和保护成员。
把派生类也变成基类的友元的友元即可。
运行一下——
这段代码是能顺利运行的,但是,我们看下面这段代码——
因为友元关系不能继承,因此我们要给派生类也变成基类友元的友元。
基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个派生类,都只有一个static成员实例。
非静态成员的继承是父类和子类各一份,地址不一样。
静态成员的继承是父类和子类共用同一份,地址也一样。
运行一下——
如上图所示。
事先说明:多继承是个大坑!!!
基类数据越多,这两个问题越严重。
数据冗余:如下图所示,Person有两个——
二义性:访问不明确~>指定类域勉强解决
菱形继承——多继承延伸的坑
多继承不是问题,多继承实现的菱形继承才是问题。
因此设计了“菱形虚拟继承”来解决,下面我们会介绍虚继承。
关键词virtual加在腰部位置,如下图所示——
都加上virtual可不可以?——当然不行。
换个说法,药能多吃吗?会影响底层的空间模型,能编译通过但底层空间会乱。
虚继承太复杂了,无论是使用还是底层,都太复杂。
不要玩菱形继承!!!当然,菱形继承也是有应用的,库里面的IO库就是搞成菱形继承的,IO库的使用会专门在IO库讲。
运行一下——
我们可以设计出多继承,但是不建议设计出菱形继承,因为菱形虚拟继承以后,无论是使用还是底层都会复杂很多。当然有多继承语法支持,就一定存在会设计出菱形继承,像Java是不支持多继承的,就避开了菱形继承。
下面说法正确的是( )A. p1 == p2 == p3 B. p1 < p2 < p3C. p1 == p3 != p2 D. p1 != p2 != p3
正确答案:C。
运行一下——
1、public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。2、组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。3、继承允许你根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称为白箱复用(white-boxreuse)。术语“白箱”是相对可视性而言:在继承方式中,基类的内部细节对派生类可见。继承一定程度破坏了基类的封装,基类的改变,对派生类有很大的影响。派生类和基类间的依赖关系很强,耦合度高。4、对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-boxreuse),因为对象的内部细节是不可见的。对象只以“黑箱”的形式出现。组合类之间没有很强的依赖关系,耦合度低。优先使用对象组合有助于你保持每个类被封装。5、优先使用组合,而不是继承。实际尽量多去用组合,组合的耦合度低,代码维护性好。不过也不太那么绝对,类之间的关系就适合继承(is-a)那就用继承,另外要实现多态,也必须要继承。类之间的关系既适合用继承(is-a)也适合组合(has-a),就用组合。
is-a用继承,has-a用组合。
运行一下——
白盒测试:更加难,一般由研发人员写并且测试,看得见、透明——保护、私有都可使用;黑盒测试:看不见,不透明;白盒 / 黑盒好坏的依据是从软件设计角度出发的。
高内聚,低耦合——可维护性(其中一个修改,另一个不受影响)。
打成一个个模块,哪个出问题改哪个,不受影响。
组件:静态库、动态库——不可执行的二进制文件——
如下图所示——
实践的角度:优先使用组合;既符合继承也符合组合,我们使用组合;但是要注意:是“优先使用组合”,不是必须使用,但是像多态这些需要继承的地方还是要用继承。