C++之父Bjarne Stroustrup对C++使用者的忠告(二)

2014-11-24 12:52:39 · 作者: · 浏览: 7
到名字空间里,以避免全局名字。

[9] 将头文件做成自给自足的。

[10] 区分用户界面和实现界面。

[11] 区分一般用户界面和专家用户界面。

[12] 在有意向用于非C++程序组成部分的代码中,应避免需要运行时初始化的非局部对象。

第10 章类

[1] 用类表示概念。

[2] 只将public 数据(struct)用在它实际杀过那仅仅时数据,而且对于这些数据成员并不存在不变式的地方。

[3] 一个具体类型属于最简单的类。如果有用的话,就应该尽可能使用具体类型,而不要采用更复杂的,也不要用简单的数据结构。

[4] 只将那些需要直接访问类的表示的函数作为成员函数。

[5] 采用名字空间,使类与其协助函数之间的关系更明确。

[6] 将那些不修改对象值的成员函数做成const 成员函数。

[7] 将那些需要访问类的表示,但无须针对特定对象调用的成员函数做成static 成员函数。

[8] 通过构造函数建立起类的不变式。

[9] 如果构造函数申请某种资源,析构函数就应该释放一资源。

[10] 如果在一个类里有指针成员,它就要有复制操作(包括复制构造函数和复制赋值)。

[11] 如果在一个类里有引用成员,它就可能需要有复制操作(包括复制构造函数和复制赋值)。

[12] 如果一个类需要复制操作或析构函数,它多半还需要有构造函数、析构函数、复制赋值函数和复制构造函数。

[13] 在复制赋值函数里需要检查自我赋值。

[14] 在写复制构造函数时,请小心地复制每个需要复制的元素(当心默认的初始式)。

[15] 在向某个类中添加新成员函数时,一定要仔细检查,看是否存在需要更新的用户定义构造函数,以使它能够初始化新成员。

[16] 在类声明中需要定义整型常量时,请使用枚举。

[17] 在构造全局的和名字空间的对象时,应避免顺序依赖性。

[18] 用第一次开关去缓和顺序依赖性问题。

[19] 请记住,临时对象将在建立它们的那个完整表达式结束时销毁。

第11 章运算符重载

[1] 定义运算符主要是为了模仿习惯使用方式。

[2] 对于大型运算对象,请使用const 引用参数类型。

[3] 对于大型的结果,请考虑优化返回方式。

[4] 如果默认复制操作对一个类和合适,最好是直接用它。

[5] 如果默认复制操作对一个类不和合适,重新定义它,或者禁止它。

[6] 对于需要访问表示的操作,优先考虑作为成员函数而不是作为非成员函数。

[7] 对于不访问表示的操作,优先考虑作为非成员函数而不是作为成员函数。

[8] 用名字空间将协助函数与“它们的”类关联起来。

[9] 对于对称的运算符采用非成员函数。

[10] 用()作为多维数组的下标。

[11] 将只有一个“大小参数”的构造函数做成explicit。

[12] 对于非特殊的使用,最好是用标准string 而不是你自己的练习。

[13] 要注意引进隐式转换的问题。

[14] 用成员函数表达那些需要左值作为其左运算对象的运算符。

第12 章派生类

[1] 避免类型域。

[2] 用指针和引用避免切割问题。

[3] 用抽象类将设计的中心集中到提供清晰的界面方面。

[4] 用抽象类是界面最小化。

[5] 用抽象类从界面中排除实现细节。

[6] 用虚函数是新的实现能够添加进来,又不会影响用户代码。

[7] 用抽象类去尽可能减少用户代码的重新编译。

[8] 用抽象类是不同的实现能够共存。

[9] 一个有虚函数的类应该有一个虚析构函数。

[10] 抽象类通常不需要构造函数。

[11] 让不同概念的表示也不同。

第13 章模板

[1] 用模板描述需要使用到许多参数类型上去的算法。

[2] 用模板表述容器。

[3] 为指针的容器提供专门化,以减小代码规模。

[4] 总是在专门化之前声明模板的一般形式。

[5] 在专门化的使用之前先声明它。

[6] 尽量减少模板定义对于实例化环境的依赖性。

[7] 定义你所声明的每一个专门化。

[8] 考虑一个模板是否需要有针对C 风格字符串和数组的专门化。

[9] 用表述策略的对象进行参数化。

[10] 用专门化和重载为同一概念的针对不同类型的实现提供统一界面。

[11] 为简单情况提供简单界面,用重载和默认参数去表述不常见的情况。

[12] 在修改为通用模板之前,在具体实例上排除程序错误。

[13] 如果模板定义需要在其他编译单位里访问,请记住写export。

[14] 对大模板和带有非平凡环境依赖性的模板,应采用分开编译的方式。

[15] 用模板表示转换,但要非常小心地定义这些转换。

[16] 如果需要,用constraint()成员函数给模板的实参增加限制。

[17] 通过显式实例化减少编译和连接时间。

[18] 如果运行时的效率非常重要,那么最好用模板而不是派生类。

[19] 如果增加各种变形而又不重新编译是很重要的,最好用派生类而不是模板。

[20] 如果无法定义公共的基类,最好用模板而不是派生类。

[21] 当有兼容性约束的内部类型和结构非常重要时,最好用模板而不是派生类。

第14 章异常处理

[1] 用异常做错误处理。

[2] 当更局部的控制机构足以应付时,不要使用异常。

[3] 采用“资源申请即初始化”技术去管理资源。

[4] 并不是美国程序都要求具有异常时的安全性。

[5] 才用“资源申请即初始化”技术和异常处理器去维持不变式。

[6] 尽量少用try 块,用“资源申请即初始化”技术,而不是显式的处理器代码。

[7] 并不是美国函数都需要处理每个可能的错误。

[8] 在构造函数里通过抛出异常指明出现失败。

[9] 在从赋值中抛出异常之前,式操作对象处于合法状态。

[10] 避免从析构函数里抛出异常。

[11] 让main()捕捉并报告所有的异常。

[12] 使正常处理代码和错误处理代码相互分离。

[13] 在构造函数里抛出异常之前,应保证释放在此构造函数里申请的所有资源。

[14] 使资源管理具有层次性。

[15] 对于主要界面使用异常描述。

[16] 当心通过new 分配的内存在发生异常时没有释放,并由此而导致存储的流失。

[17] 如果一函数可能抛出某个异常,就应该假定它一定会抛出这个异常。

[18] 不要假定所有异常都时由excepion 类派生出来的。

[19] 库不应该单方面终止程序。相反,应该抛出异常,让调用者去做决定。

[20] 库不应该生成面向最终用户的错误信息。相反,它应该抛出异常,让调用者去做决定。

[21] 在设计的前期开发出一种错误处理策略。

第15 章类层次结构

[1] 利用常规的多重继承表述特征的合并。

[2] 利用多重继承完成实现细节与界面分离。

[3] 用virtual 基类表达在类层次结构里对某些类(不是全部类)共同的东西。

[4] 避免显式的类型转换(强制)。

[5] 在不可避免地需要漫游类层次结构的地方,使用dynamic_cast。

[6] 尽量使用dynamic_cast 而不是typeid。

[7] 尽量使用private 而不是protected。

[8] 不要声明protected 数据成员。

[9] 如果某个类定义了operator delete(),它也应该有虚析构函数。

[10] 在构造和析构期间不要调用虚函数。

[11] 尽量少用为解析成员名而写的显式限定词,最好时在覆盖函数里用它。

第16 章库组织和容器

[1] 利用标准库功能,以维持可移植性。

[2] 决不要另行定义标准库的功能。

[3] 决不要认