继承与OOP
# 继承与OOP, Inheritance and Object-Oriented Design
单一继承与多重继承
public继承,private继承, protected继承
class Person{ ... } class Student : public Person{ ... }
1
2virtual / non-virtual 继承
成员函数和其他语言特性的影响
- 缺省参数与virtual函数的影响?
- 继承如何影响C++函数名臣的查找规则?
- 设计选项
- class行为如果要修改, virtual函数是最佳选择吗?
# Item 32:确定你的public继承塑模出is-a关系 Make sure public inheritancemodels"is-a."
public继承的时候, 确认两个对象是 is a的关系;多态通过虚函数来完成,
- 什么时候用虚函数?什么时候用纯虚函数?
# Item 33:避免遮掩继承而来的名称 Avoid hiding inherited names.
- 继承的时候,注意类内部的变量名称是否会被覆盖,
- 即使是重载的函数,不管函数接口形式是否一样, 也会被子类的同名函数覆盖
- 使用using Base::mf3() 可以指定在子类作用域范围里面使用base类的mf3函数,
- 如果只想使用某一个mf3(), 只能是子类的函数里面, 再调用Base::mf3(); 这种方式叫forward functions;
# Item 34:区分接口继承和实现继承 Differentiate between inheritance of interface and inheritance of implementation.
- 什么是接口继承和实现继承?
- pure virtual函数的目的就是接口继承, 但是也可以有一份基类实现,调用的时候只能通过子类指定父类名称的方式来调用(纯虚函数必须重写);
- 非纯虚函数是为了让子类继承接口 + 缺省实现, 这些都是自动继承的, 如果子类不override 虚函数的话(一般虚函数可以重写, 也可以不重写);
- 非虚函数的目的是强制让子类继承一个缺省的实现;(非虚函数,没有多态性,直接继承)
- 接口和实现继承分开, 也就是把接口用一个纯虚函数来声明, 实现使用一个private或者protected的缺省实现来代替, 这样子类必须要重写纯虚函数,但是可以默认使用缺省的实现;
- 也可以使用一个虚函数的非虚实现, 然后再在子类里面overide的时候调用这个函数;
# Item 35:考虑virtual函数以外的其他选择 Consider alte rnatives to virtual functions.
- 除了virtual函数之外,也可以考虑一下其他的选择
- 通过一个public函数, 调用自己的virtual函数, non-virtual interface(NVI)方法;(模板方法设计模式), 子类就
- 借助funciion pointer实现strategy模式
- 使用各个库里面的function component来实现strategy模式, 例如std::function, 而且这个东西支持任何callable entities,包括运算符重载的struct和class
- 标准设计模式, 古典的strategy模式, 就是使用pImple的方式来实现strategy, 来代替第一条里面的实现方式
# Item 36:绝不重新定义继承而来的non-virtual函数 Never redefine an inherited non-virtual function.
- 不要重新定义继承来的non virtual函数, 这其实是一种overloading, 并不能实现多态特性的overide, nonvirtual 函数其实是静态绑定的(dynamic binding);virtual函数是动态绑定(dynamic binding)
# Item 37:绝不重新定义继承而来的缺省参数值 Never redefine a function's inherited default parameter value.
- 不要重新定义继承来的缺省参数值, 因为可能会在调用子类的时候, 用到父类里面这个函数的默认值,(对于通过对象指针, 引用的方式都会有这个问题, 因为默认参数的绑定是一种静态绑定),子类就声明参数就可以了, 不需要有默认值
# Item 38:通过复合塑模出has-a或“根据某物实现出” Model"has-a"or"is-implemented-in-terms-of"through composition.
通过composition实现has a, 或者根据某物实现的关系
- 要区分, composite和interitate之间的区别(复合与继承之间的关系)
# Item 39:明智而审慎地使用private继承 Use private inheritance judiciously.
- 谨慎使用private继承,
- 编译器不会把一个private继承的子类,自动转换成一个基类
- private继承下来的所有成员, 在子类中都会变成private属性
- protect继承
- 默认的基本上都是public继承;
- 尽可能使用compiosition, 必要的时候再使用private继承
# Item 40:明智而审慎地使用多重继承 Use multiple inheritance judiciously.
- 谨慎使用多重继承(子类从多个父类继承而来)
- 可能对导致对基类函数调用的歧义,到底调用的是哪一个基类的成员函数?
- 钻石形继承, 二级基类可以是虚基类(virtual继承), 这样三级再继承的时候, 就不会重复出现两个爷爷类里面的成员函数了;
- virtual继承会带来更多大小,速度,初始化的成本。如果非要有一个virtual base class, 最好不要在虚基类里面放置数据;
- 有一种情况, 比较适合多重继承,public继承某个interface class, private继承某个协助实现的class;帮助子类实现某些功能。但是还是谨记第一条吧;