所谓软件设计,是“令软件做出你希望它做的事情”的步骤和做法,通常以颇为一般性的构想开始,最终演变成十足的细节,以允许特殊接口(interfaces)的开发。这些接口而后必须转换为C++声明式
18 Make interfaces easy to use correctly and hard to use incorrectly
tr1::shared_ptr
缺省的删除器来自“tr1::shared_ptr
诞生所在的那个DLL
”的delete
, 这个特性可以避免“corss-DLL problem
”问题;- 好的接口很容易被正确使用,不容易被误用;
- 促进正确使用的办法包括接口的一致性,以及与内置类型的行为兼容;
- 避免误用的办法包括建立新类型、限制类型上的操作,束缚对象值,以及消除客户的资源管理责任;
19 Treat class design as type design
- Class的设计就是type的设计。
20 Prefer pass-by-reference-to-const to pass-by-value
- 缺省情况下
C++
以by value
方式传递对象至函数。除非另外指定,否则函数参数都是以实际实参的复件为初值,而调用端所获得的亦是函数返回值的一个复件这些复件是由对象的copy
构造函数产出,这可能使得pass-by-value
成为费时的操作; - 尽量以
pass-by-reference-to-const
替换pass-by-value
,前者通常比较搞笑,并可避免切个问题(slicing problem
); - 上条规则并不适用于内置类型,以及
STL
的迭代器和函数对象,对这些而言pass-by-value
往往更合适;
21 Don’t try to return a reference when you must return an object
- 绝不要返回
pointer
或者referenc
指向一个local stack
对象,或返回reference
指向一个heap-allocated
对象,或返回pointer
或reference
指向一个local static
对象
22 Declare data members private
- 成员变量应该是
private
; protected
成员变量并不比public
具有封装性;public
继承不改变基类成员的访问权限;protected
继承将基类中public
成员变为子类的protected
成员,其它成员的访问权限不变;private
继承使得基类所有成员在子类中的访问权限变为private
;public
属性的成员函数或变量:可以被该类中的函数、子类的函数、其友元函数访问,也可以由该类的对象访问;protected
属性的成员函数或变量: 可以被该类中的函数、子类的函数、以及其友元函数访问,但不能被该类的对象访问;private
属性的成员函数或变量: 只能由该类中的函数、其友元函数访问,不能被任何其他访问,该类的对象也不能访问;
23 Prefer non-member non-friend functions to member functions
- 宁以non-member、non-friend替换member函数。这样做可以增加封装性、包裹弹性和机能扩充性;
24 Declare non-member functions when type conversions should apply to all parameters
- 如果你需要为某个函数的所有参数(包含被
this
指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member
;
25 Consider support for a non-throwing swap
- 当
std::swap
对你的类型效率不高时,提供一个swap
成员函数,并确定这个函数不抛出异常; - 如果你提供一个
member swap
,也该提供一个non-member swap
用来调用前者。对于classes
,也请特化std::swap
; - 调用
swap
时应针对std::swap
使用using
声明式,然后调用swap
并且不带任何“命名空间资格修饰”; 为“用户定义类型”进行
std template
全特化是好的,但千万不要尝试在std
内加入某些对std而言全新的东西;偏特化:任何针对模版参数进一步进行条件限制设计的特化版本;
- 完全特化:针对所有的模版参数进行特化;
- 函数模版不存在偏特化,只有类模版才能偏特化;
- 客户可以全特化
std
内的templates
,但不可以添加新的templates
(templates classes
或templates functions
或其他任何模板东西放到std里面); - 一旦编译器看到对
swap
的调用,它们便查找适当的swap并调用之。C++
的名称查找法则(name lookup rules
)确保将找到global
作用域或T所在之命名空间内的任何T
专属的swap
;