1 能用前置声明的地方尽量不使用 #include.
前向声明有效:
函数的参数或返回值
成员变量为该类的引用或指针
静态成员变量
无效:
继承关系
含有该类型的非静态数据成员
2 内联函数
谨慎对待析构函数, 析构函数的内联
内联那些包含循环或 switch 语句的函数常常是得不偿失
虚函数和递归函数就不会被正常内联.
2 #include 的路径及顺序
如, dir/foo.cc 的主要作用是实现或测试 dir2/foo2.h 的功能, foo.cc 中包含头文件的次序如下:- dir2/foo2.h (优先位置, 详情如下)
- C 系统文件
- C++ 系统文件
- 其他库的 .h 文件
- 本项目内 .h 文件
主要是为了避免隐藏依赖。
3 命名空间
匿名的命名空间可以取代static关键字, 但会被全局变量覆盖。匿名空间禁止在头文件中使用。
amespace a { class A; } // a::A 的前置声明
// 允许: .cc 文件中, .h 文件的话, 必须在函数, 方法或类的内部使用 using foo::x;// 以及命名空间别名 namespace fbz = ::foo::bar::baz;
不要将嵌套类定义成公有, 除非它们是接口的一部分, 比如, 嵌套类含有某些方法的一组选项.
使用静态成员函数或名字空间内的非成员函数, 尽量不要用裸的全局函数.
4 变量
禁止使用 class 类型的静态或全局变量: 它们会导致很难发现的 bug 和不确定的构造和析构函数调用顺序.
静态生存周期的对象, 包括全局变量, 静态变量, 静态类成员变量, 以及函数静态变量, 都必须是原生数据类型 (POD : Plain Old Data)
5 类
构造函数中只进行那些没什么意义的 (trivial, 简单初始化对于程序执行没有实际的逻辑意义)初始化,
使用 Init() 方法集中初始化有意义的 (non-trivial) 数据.
如果一个类定义了若干成员变量又没有其它构造函数, 必须定义一个默认构造函数. 否则编译器将自动生产一个很糟糕的默认构造函数.
对单个参数的构造函数使用 C++ 关键字 explicit.
仅在代码中需要拷贝一个类对象的时候使用拷贝构造函数; 大部分情况下都不需要, 此时应使用 DISALLOW_COPY_AND_ASSIGN.
仅当只有数据时使用 struct, 其它一概使用 class.
为了和 STL 保持一致, 对于仿函数 (functors) 和特性 (traits) 可以不用 class 而是使用 struct.
真正需要用到多重实现继承的情况少之又少. 只在以下情况我们才允许多重继承: 最多只有一个基类是非抽象类; 其它基类都是以 Interface 为后缀的 纯接口类
重载还有令你吃惊的副作用. 比如, 重载了 operator& 的类不能被前置声明.
倾向编写简短, 凝练的函数.
仅在输入参数类型不同, 功能相同时使用重载函数 (含构造函数). 不要用函数重载模拟 缺省函数参数.
C++ 内建整型中, 仅使用 int. 如果程序中需要不同大小的变量, 可以使用 <stdint.h> 中长度精确的整型, 如 int16_t.