内容简介:作者:LogM本文原载于
作者:LogM
本文原载于 https://segmentfault.com/u/logm/articles ,不允许转载~
4. 设计与声明
-
4.1 条款18:让接口不易被误用
- 简单来说,就是考虑用户可能的误用行为,在代码中规避。比如工厂函数返回值为"智能指针"类型,避免用户使用一般指针管理资源带来的资源泄漏风险;比如将 operator* 的返回类型设为const,避免用户写出"a*b=c"这样的代码。
-
4.2 条款19:像设计type一样设计class
- 作者的意思是,设计class要考虑很多细节,尽量使设计出来的class像C++内置类型一样有极大的可用性和鲁棒性。
-
4.3 条款20:宁以 pass-by-reference-to-const 替换 pass-by-value
- 原因:a. 参数使用引用传递,不需要构造新对象,比较快;b. 避免对象切割问题。
-
对象切割(slicing):当派生类对象以 by-value 方式传递参数并被视为基类对象,基类的拷贝构造函数在构造时会把派生类特有的性质抹除。
-
"引用"在编译器底层的实现就是指针(指针的本质是int类型的变量),所以在以下场景,"引用"并不一定比pass-by-value快:a. C++内置类型;b. STL的迭代器(底层实现是指针);c. 函数对象(底层实现是指针)。
-
4.4 条款21:不要让函数返回值是指向局部变量的引用或指针
- 原因应该很容易理解:局部变量在函数调用结束后就销毁了,那么这个函数返回的引用和指针指向的内存已经无效了。
-
4.5 条款22:将成员变量声明为 private
- 一致性:成员变量为 private,则用户想访问成员变量必须通过成员函数,所以用户就不用试着记住是不是要加括号,因为成员函数都要加括号。
- 安全性:通过成员函数控制用户对成员变量的读写权限。
- 封装性:class的版本发生变化,但提供给用户的API还是可以保持不变。
-
4.6 条款23:宁以 non-menber、non-friend 替换 member 函数
- 使用场景如下代码所示。作者倾向于non-member、non-friend的理由是:它们无法访问private的成员变量,在封装性上更好,编译时候的依赖程度也低。
-
作者的说法有一定道理,但我不完全同意作者的观点:
- a. member函数可以访问private的成员变量,并不意味着用户就可以接触到private的成员变量,你在写代码的时候不让这个member函数访问private的成员变量不就可以了?(此时问题变成了:如何确保写代码的人不在这个函数中滥用private的成员变量)
- b. 有些情况,使用non-member、non-friend函数会降低代码接口的一致性。作者的解决思路是把non-member、non-friend函数放在和类同一个namespace下,我想了想,这么做一致性还是不如直接写member函数。
-
class WebBrowser { public: ... void clearCache(); void clearHistory(); void clearCookies(); ... } //假如现在要写一个函数clearEverything(),作用是同时清理cache、history、cookies。 //使用member函数的情况 class WebBrowser { public: ... void clearEverything(); ... } void WebBrowser::clearEverything() { clearCache(); clearHistory(); clearCookies(); } //使用non-member函数的情况 void clearBrower(WebBrowser& wb) { wb.clearCache(); wb.clearHistory(); wb.clearCookies(); }
-
4.7 条款24:若所有参数都需要类型转换,请把这个函数写成 non-member 函数
-
//第一种情况:乘法函数为member函数 class Rational { public: ... Rational(int numerator, int denominator); Rational(int num); //这个构造函数使得该类支持从int到Rational的类型转换。如果前面加explict则说明不支持隐式类型转换仅支持显式转换,现在没加,支持隐式转换 const Rational operator* (const Rational& rhs) const; } //使用 Rational lhs(1, 9); Rational result; result = lhs * 2; //ok,2不是Rational类型,但可以发生隐式类型转换 result = 2 * lhs; //bad,2不是Rational类型
-
//第二种情况:乘法函数为non-member函数 class Rational { public: ... Rational(int numerator, int denominator); Rational(int num); //这个构造函数使得该类支持从int到Rational的类型转换 } const Rational operator* (const Rational& lhs, const Rational& rhs) { ... } //使用 Rational lhs(1, 9); Rational result; result = lhs * 2; //ok,2不是Rational类型,但可以发生隐式类型转换 result = 2 * lhs; //ok,2不是Rational类型,但可以发生隐式类型转换
-
-
4.8 条款25:考虑写出一个不抛异常的swap函数
-
STL库中
std::swap
的典型实现如下代码,这个实现比较平淡。对于某些类,写一个模板特化的swap执行效率会更高。作者介绍了怎么自己写std::swap
的特化版本,这边就不展开了。 -
namespace std { //平淡的std::swap实现 template<typename T> void swap(T& a, T& b) { T temp(a); a = b; b = temp; } }
-
STL库中
以上所述就是小编给大家介绍的《【读书笔记】Effective C++(04)设计与声明》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 【Tomcat学习笔记】组件声明周期
- 【Tomcat学习笔记】组件声明周期
- Go语言笔记 | 04-短变量声明
- Go语言笔记 | 03-变量的声明和初始化
- JS变量声明和函数声明提升
- JavaScript声明变量详解
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Probability and Computing
Michael Mitzenmacher、Eli Upfal / Cambridge University Press / 2005-01-31 / USD 66.00
Assuming only an elementary background in discrete mathematics, this textbook is an excellent introduction to the probabilistic techniques and paradigms used in the development of probabilistic algori......一起来看看 《Probability and Computing》 这本书的介绍吧!