首页 > 代码库 > Effective c++关键点(二)

Effective c++关键点(二)

条款18: 让接口容易被正确使用,不易被误用


18.1 考虑接口可能被怎样误用
18.2 自定义新类型对接口使用做限制
18.3 以函数替代对象
18.4 在类型内限制什么事可做,什么事不能
18.5 尽量使自定义类型行为与内置类型行为一致
18.6 不要寄希望于客户必须记得做某些事情
18.7 shared_ptr在销毁时会自动使用定义时指定的删除器



条款19: 设计class如设计type


19.1 新type的对象应该如何被创建和销毁?
19.2 对象的初始化和对象的赋值该有什么样的差别
19.3 新type的对象如果被passed by value(以值传递),意味着什么
19.4 什么是新type的"合法值"
19.5 新type是否需要配合某个继承体系
19.6 新type是否需要与其他type转换
19.7 新type需要哪些操作符和函数
19.8 什么样的成员函数应该私有
19.9 新type的成员的读取权限
19.10 定义一个class还是class template
19.11 什么是新type的"未声明接口" 



条款20:宁以pass-by-reference-to-const 替换pass-by-value


20.1 缺省情况下C++以by value方式(一个继承自C的方式)传递对象至(或来自)函数。
20.2 以by reference方式传递参数可以避免slicing(对象切割)问题
20.3 内置类型(例如int)与STL的迭代器和函数对象 , pass by value往往比pass by reference的效率高些



条款21: 必须返回对象时,别妄想返回其reference


21.1 绝不要返回pointer或reference指向一个local stack对象
21.2 绝不要返回reference指向一个heap-allocated对象
21.3 绝不要返回pointer或reference指向一个local static对象而有可能同时需要多个这样的对象



条款22: 将成员变量声明为private


22.1 以函数形式访问成员变量实现读写控制


条款23: 宁以non-member、non-friend替换member函数


23.1 从封装性角度看,non-member、non-friend函数使class有更大的封装性
23.2 class 定义式对客户而言是不能扩展的,而命名空间namespace是可扩展的



条款24: 若所有参数皆需类型转换,请为此采用non-member函数


24.1 例:操作符重载


条款 25: 考虑写出一个不抛异常的 swap 函数


25.1 令non-member swap调用member swap
25.2 为class特化std 命名空间内的 swap函数
25.3 调用swap前,最好声明using std::swap
25.4 当从class没有member swap特化和non-member swap特化时,才调用std::swap



条款26: 尽可能延后变量定义式的出现时间


26.1 避免变量未被使用,而额外调用构造函数和析构函数


条款27: 尽量少做转型动作


27.1 四种新式转型:
const_cast<T>( expression)
dynamic_cast<T>( expression)
reinterpret_cast<T>( expression)
static_cast<T>(expression)
27.2 dynamic_cast的许多实现版本执行速度相当慢
27.3 尽可能隔离转型动作,通常把它隐藏在某个函数内



条款28: 避免返回handles指向对象内部成分


28.1 handles包括指针,引用,迭代器
28.2 返回一个"代表对象内部数据"的handle时,会降低对象封装性
28.3 返回的handles可能悬空



条款29: 为"异常安全"而努力是值得的


29.1 以对象管理资源防止资源泄露
29.2 异常安全函数的三种保证:基本承诺,强烈保证,不抛掷保证
29.3 异常安全码必须提供三种保证之一;否则,它就不具备异常安全性。
29.4 强烈保证:copy-and-swap:修改对象数据的副本,然后在一个不抛异常的函数中将修改后的数据和原件置换



条款30: 透彻了解inlining的里里外外


30.1 inline函数的声明:明确声明,隐式声明
30.2 即使是inline函数,有时编译器也为函数生成一个outline函数本体(如:取某个inline函数的地址时)
30.3 改变inline函数时,客户端需要重新编译,而对于non-inline函数,客户端只需重新链接



条款31: 将文件间的编译依存关系降至最低


31.1 让头文件尽可能不依赖其他文件,最坏让它与其他文件内的声明式(而非定义式)相依赖。
31.2 如果使用object references 或object pointers 可以完成任务,就不要使用object。(定义object需要用到类型的定义式)
31.3 声明一个函数用到某个class时只需要该class的声明式
31.4 为声明式和定义式提供不同的头文件。
31.5 Handle classes和Interface classes:



条款32: 确定public继承塑造出is-a关系


32.1 "public继承"意味is-a 关系


条款33: 避免隐藏继承而来的名称


33.1 使用using 声明继承而来的名称
33.2 转交函数(forwarding functions)



条款34: 区分接口继承和实现继承


34.1 函数接口(function interfaces) 继承和函数实现(function implementations)继承。
34.2 声明一个纯虚函数时,derived classes只继承函数接口。
34.3 声明一个非纯虚函数时,derived classes继承该函数的接口和缺省实现。
34.4 声明一个非虚函数时,derived classes继承函数的接口及一份强制性实现。



条款35: 考虑virtual函数以外的其他选择


35.1 non-virtual interface(NVI)手法
35.2 由函数指针(Function Pointers)实现Strategy模式
35.3 由trl::function 完成Strategy模式



条款36: 绝不重新定义继承而来的non-virtual 函数


36.1 用于base对象的,也适用于derived对象
36.2 derived classes一定会继承non-virtual 函数的接口和实现
36.3 重新定义会隐藏base class的non-virtual函数


条款37: 绝不重新定义继承而来的缺省参数值


37.1 virtual函数是动态绑定,而函数的缺省参数值是静态绑定的,即实际对象为driver对象的base指针(或引用)调用virtual函数时,缺省参数值由base的virtual函数确定。


条款38: Model"has-a"or"is-implemented-in-terms-of"through composition.


38.1 在应用域,复含意味has-a。在实现域,复合意味is-implemented-in-terms-of。


条款39: 明智而审慎地使用private继承


39.1 private继承时,编译器不会自动将一个derived class对象转换为base class对象
39.2 private继承意味implemented-in-terms-of,不是因为B对象和D对象存在有任何观念上的关系
39.3 is-implemented-in-terms-ot关于组合和Private继承的选择:当需要protected 成员或virtual 函数时,
39.4 private继承:empty base最优化
EBO:空白基类最优化。
空白基类:没有non-static成员变量,没有virtual函数,也没有virtual base classes 



条款40: 明智而审慎地使用多重继继承


40.1 虚继承与虚基类