http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#The__define_Guard
Gist:
- 头文件:
- #define: <PROJECT>_<PATH>_<FILE>_H_.
- #include: 当forward declaration(for example: class A;) 够用时别再用#include了
- 在没有类定义的情况下(For example, only declare class Foo), 依然可用的有:
- 数据成员是Foo* or Foo&
- 函数的参数是Foo
- static数据成员是Foo
- 在没有类定义的情况下(For example, only declare class Foo), 依然可用的有:
- inline:
- 不要inline 超过10行代码的函数
- 尽量不要inline析构函数,因为析构函数会对父类的析构函数有潜在的调用
- 不要inline有循环或者switch的函数
- vitural, recursive函数一般不会被编译器认可为inline.
- inline file
- file name with -inl.h suffix
- inline函数要定义在头文件里,简单的直接放在.h里,复杂的放在-inl.h里
- -inl.h 同样放置模板函数的定义
- 函数参数顺序
- input -> output
- input: const reference. output/input: non-const pointers
- include头文件的顺序
- preferred files(with our main purpose), C library, C++ library, other libraries'
.h
, your project's.h
在上面满足的情况下,按字母排
- preferred files(with our main purpose), C library, C++ library, other libraries'
Scoping
Namespace
匿名的namespace是鼓励的。 但是小心不注意违反了C++ ODR原则。
在.h里别用匿名的namespace
named namespace wrap在 include, 全局的定义和申明, 其他namespace 的forward的class声明之后
不能用using-directive把整个namespace包含进来, 但包含specific的方法,class是允许的,namespace alias也是允许的(但是要避免在公共的头文件里用)。
Nested Class
nested class 只能在包含它的类里forward-declared, 其他要使用nested class只能inlcude整个头文件定义
尽量不要把nest class public, 除非是接口的一部分
全局函数,static member, nonmember函数
尽量不要定义全局函数,而是放到匿名namespace或者static-linkage里来限制范围
本地变量
在声明的时候初始化
为了节省消耗,在loop外定义变量
声明离使用越近越好
静态以及全局变量
由于静态,全局变量初始化的不确定性,不允许静态或者全局变量是非POD类型
即使是POD对象,初始化不能依赖于可能发生初始化不确定性的函数
实在需要非POD的话,可以申明为指针,并且在初始化确定的函数中初始化(main or pthread_once)
Classes
构造函数
构造函数应该只放置成员变量的初始化,复杂的其他操作放到额外的init方法里。
禁止在构造函数使用exception特性
禁止在构造函数里使用virtual 函数,因为这里virtual函数不会dispatch
构造函数里不要访问潜在的全局变量
always至少创建无参数的构造函数,不要交给compiler来做
为了防止implict conversion, 在只有一个参数的构造函数前加explict, 如果有例外要用comments说明
拷贝构造函数
可以避免使用拷贝构造函数,比如改用pointer, reference在stl container中或者函数参数中
不需要copyable的时候,把拷贝构造函数和赋值函数都要显式禁止了
如果需要copyable, 尽量另外定义拷贝函数而不是使用拷贝构造函数,eg CopyFrom
Struct vs. Class
只有当纯数据集合的时候才用struct, 并且struct里的函数只能和数据提取/设置有关, 其他的用class
继承
分为实现继承和接口继承
继承要public inheritance
对于实现继承,组合会是更好的选择
对于子类的析构函数要为virtual, 如果class有virtual的函数
禁止protected member function/variable
重新实现virtual 函数,必须在前面同样加上virtual
多重继承
多重继承只能用在一个是真正父类, 其他都是接口;或者全是接口类的情况下
接口类
suffix with Interface
只有纯虚函数或者static成员函数
没有非static成员变量
只能有protected的无参数构造函数
访问控制
除了static const成员变量外,其他的都为private,并且提供set/get函数去访问
命名规则:var: a_; getter: a(); setter: set_a()
setter/getter一般inline在.h里
类成员声明顺序
public -> protected -> private
- Typedefs and Enums
- Constants (
static const
data members) - Constructors
- Destructor
- Methods, including static methods
- Data Members (except
static const
data members)
- 操作符重载
- 尽量不要重载操作符, 如果实在要做,comment他
- 不要重载&, 因为如果重载了会导致forward declare可能不安全
Others
参数
input: value/const reference/const pointer
ouput: pointer
不允许non-const reference
重载函数
尽量用make sense 的函数名来代替重载函数, 让读者不看参数也能知道调用的是什么函数
函数参数默认值
为了防止copy-paste的时候发现旧的code在新的code里不适合,但是因为有默认值看不出来的情况,不要使用函数参数默认值,除非为了模仿可变长参数
友元
可以使用友元,在设计unittest的时候可以把unittest class作为 tested class的友元类
异常
不使用异常。。。。
异常安全代码的编写, 异常安全是指发生异常的时候会rollback回异常前的初始状态,所以不会对系统有影响http://www.newasp.net/tech/program/20148.html
RTTI
不使用RTTI, 可能就改用double-dispatch solution, 像 visitor design
Casting
不要使用c-style casting, 像int x = (int)y;
用const_cast 去掉const
用static_cast代替c-sytle cast来转换值类型, 或者显式的把pionter转对
除了在unit code里,其他地方不要使用dynamic_cast
用reinterpret_cast去进行指针之间或者指针和int之间的不安全的转换
Stream
别使用stream, 用printf +
read
/write代替
Preincrement and Predecrement
用Preincrement and Predecrement代替post-, 如果效果一样的情况下
Const
尽量使用const, 在成员函数,变量中
任何不变的地方都用const
Int
注意int和uint
用stdint里的int32_t等来明确指定长度,当需要的时候
64位兼容性
当要算指针的时候,用intptr_t代替
sizeof(void*) != sizeof(int)
注意strcuture alignment
Macro
尽量不用##生成名称
不要再.h里定义macro
0和NULL
对应int用0, 指针用NULL,char用‘/0'
sizeof
用sizeof(varname)代替sizeof(type), 因为var很可能会换type, 如果用type就太死板了