1. 引用参数
(1)将值或常引用作为输入参数,指针作为输出参数是谷歌的一个惯例。
2. 函数重载
(1)利:可以使代码更直观。对模板化的代码,重载可能是必须的。对访问控制器的实现,重载也是很方便的。
(2)弊:函数仅以参数类型不同来重载,则需要深入理解参数匹配规则。子类重写基类函数也会引起迷惑。
(3)重载时,考虑根据其参数名来命名函数。如 AppendString() 比 Append() 好。
3. 默认参数
(1)默认参数会引起代码更难维护的问题。
4. 可变长度数组和内存申请
(1)可变长度数组和 alloc() 不是 C++ 标准的一部分,根据程序栈容量来申请空间,可能引起内存覆盖缺陷。
(2)使用更安全的内存申请函数,如 scoped_ptr/scoped_array。
5. 友元
(1)适度使用友元类和友元函数是允许的。
(2)友元应该和其友元类定义在同一文件中。
(3)友元仅是扩展而不是打破类的封装性。一个类需要访问另一个类的私有成员时,友元比这个成员被公有化更好。
(4)另外,类和类的协作只能通过公有成员。
6. 异常处理
(1)通常不使用 C++ 的异常处理。
7. 运行时类型信息
(1)不建议使用 RTTI。
(2)除单元测试,不要使用 RTTI。确实需要基于对象类型来完成不同的功能时,考虑替代方案。虚方法是使子类执行不同代码的首选方案。
8. 类型转换
(1)使用 static_cast 进行 C 风格的值转换,或将子类指针提升为基本指针。
(2)使用 const_cast 去掉 const 修饰。
(3)使用 reinterpret_cast 进行不安全的指针类型转换。
(4)dynamic_cast 仅用在测试中。
9. 流
(1)流(stream)的构造和析构函数会自动打开、关闭相关文件。
(2)除非需要日志接口,否则不要使用流。
10. 前置自增和前置自减
(1)不考虑返回值时,前置性能总是优于后置。如 i 是一个迭代器或非标量类型,后置需要复制 i,而复制的开销是很大的。
11. const 修饰符的使用
(1)建议使用 const 修饰的情况
a. 函数不修改通过引用或指针传递的参数值;
b. 类方法尽量定义成 const。如访问器、不修改类数据成员、不调用非 const 方法、不返回非 const 引用或指针的函数;
c. 初始化后,不需要修改的数据成员;
12. 整型类型
(1)在 stdint.h 中定义了 int16_t、uint32_t,int64_t 等整型,用到整型时,首选这些精确的类型。
(2)不要使用无符号 uint32_t,除非确切知道要存储的是一个位组而不是一个数字,或定义二进制补码溢出。
(3)不要使用无符号类型来说明一个数时非负的,应该用断言来说明。
13. 64位兼容性
(1)
// size_t的输出宏,基于inttypes.h的风格 #ifdef _LP64 #define __PRIS_PREFIX “z” #else #define __PRIS_PREFIX #endif //在printf格式字符串中的%后使用这些宏来确保正确的32/64位行为 //用法如下: // size_t size = records.size(); // printf(“%”PRIus”\n”,size); #define PRIdS __PRIS_PREFIX “d” #define PRIoS __PRIS_PREFIX “o” #define PRIuS __PRIS_PREFIX “u” #define PRIxS __PRIS_PREFIX “x” #define PRIXS __PRIS_PREFIX “X”
(2)sizeof(void*) != sizeof(int),需要指针大小的整数,使用 intptr_t。
(3)声明64位常量时,使用 LL 或 ULL 后缀。
14. 预处理宏
(1)使用宏时,应该倍加小心。尽量使用内联函数、枚举、常量来替代宏。
(2)可以避免大量使用宏引起的问题的做法
a. 不在头文件中定义宏;
b. 使用宏前定义(#define),使用后立即解定义(#undef);
c. 不要解定义一个宏后,使用它去定义另一个宏;
d. 不要使用导致不平衡 C++ 构造的宏;
e. 不要使用 # 作为函数、类、变量名称的开始;
15. 0 和 NULL
(1)整型用0、实数用0.0、指针用 NULL、字符用'\0'。
(2)GCC4.1.0 下,sizeof(NULL) 和 sizeof(0) 不相等。
16. sizeof运算符
(1)尽量使用 sizeof(varname),而不是 sizeof(type) 来确定一个变量或类型的大小。