本文章属于专栏- 概述 -《业界C++进阶建议整理》-CSDN博客
本文列出《Effective C++》的31-40条的个人理解的极精简版本。
- 31、将文件的编译依存关系降到最低
- 当class A包含数据成员B、C时,文件M依赖了A,则因为B、C在A的头文件中,所以M也依赖了B、C。要想解除这个依赖,本质上就是增加一层跳转
- 可以让A包含一个ImplA指针,将A的实现和声明分离,从而减少编译依赖,也增加了封装性
- 有一个基类,里面是要调用的虚函数,客户包含这个虚函数类,然后在派生类中去做实际的事。当然这个基类指针,最好有一个工厂类返回指定类型
- 当class A包含数据成员B、C时,文件M依赖了A,则因为B、C在A的头文件中,所以M也依赖了B、C。要想解除这个依赖,本质上就是增加一层跳转
- 32、确定你的public继承塑模出is-a关系
- is-a,意味着base class 的所有方法都可以作用在derived class上。注意正方形是一种长方形,但是我们可以对长方形的某两个边+1,但是正方形不行。所以这里不应该继承
- 33、 避免遮掩继承而来的名称
- 个人见解:非虚函数,子类和父类不要重名。如果需要重写基类的函数,使用虚函数。可以节约很多编程以及问题调查的精力
- 34、区分接口继承和实现继承
- 当强制继承接口时,要用纯虚函数,让其在编译器发现问题
- 使用pure virutal、impure virtual、non-virtual函数,分别意味着派生类是继承:仅接口、接口+默认实现、接口+强制实现
- 35、考虑virtual函数以外的其他选择
- 基类指向派生指针时,想要调用指定类别的方法时,除了用virtual
- 可以考虑基类对象存一个指针或函数对象。
- 也可以考虑存一个指向另一个基类指针(可能指向另一个继承体系的派生类),这就是设计模式中的strategy模式
- 个人见解:组合往往比继承,更容易维护和Debug
- 36、绝不重新定义继承而来的non-virtual函数
- 语意上讲:继承是is-a的关系,适用于基类的函数一定适用于派生类,覆盖基类的函数推翻了这样的语意
- 使用上讲:这个操作会导致调用的函数,不仅是和指针指向的地址相关,还和其声明相关。因为non-virtual函数是静态绑定的
- 个人见解:与33条类似。我认为放弃使用一些C++中难以记住,且收益不大的规则,是高效开发的关键。
- 37、绝不重新定义继承而来的缺省参数值
- 缺省参数值是静态绑定的,virtual函数重新定义时,会导致指向派生类的基类指针,调用的是派生类的方法,但是使用的基类的默认值。
- 如果派生类期待和基类一样的默认值,如果默认值写两份,有维护风险和代码重复的问题。最好的方法是在基类定义一个non-virtual函数,这个non-virtaul函数有默认值,其调用了一个virtual函数。派生类就是实际先调用了基类的non-virtual函数,而这个virtual函数是派生类的,且用了基类的默认值
- 个人见解:放弃把参数默认值,写到函数参数中。这个规则模糊且不实用。如果逻辑需要默认值,写到成员变量中,在继承时更容易维护
- 38、通过复合塑模出has-a或者“根据某物实现出”
- 一个核心的判断条件是A的所有方法,是否B都可以用,如果是,用B public继承A,否则B使用A时,用组合
- 39、谨慎使用private继承
- public继承:public成员和protect成员以相同形式成为派生类的成员,private成员不继承
- protect继承:public成员和protect成员都以protect形式成为派生类成员,private成员不继承
- private继承:public成员和protect成员都以private形式成为派生类成员,private成员不继承
- public继承和protect继承,派生类指针和引用可以转换为基类,但是private继承不行
- public成员:外部可以访问,派生类可以继承
- protect成员:外部不能访问,派生类可以继承
- private成员:外部不能访问,派生类不继承
- 40、谨慎使用多重继承
- 个人见解:这是一个性价比不高的功能,容易出错,且收益不高。java语言中也没有多继承。放弃它吧。