C++ Coding Style编程 |
|||
C++不少强大的语言特性致使它的复杂,其复杂性会使得代码更容易出现bug、难于阅读和维护。数组 因为,本人有一点点代码洁癖,因此依照Google的C++编程规范《Google C++ Style Guide》,用来约束本身平时编程,使得代码在有效使用C++语言特性的同时易于管理。多线程 |
|||
分类ide |
标题svn |
规则函数 |
备注(示例)性能 |
头文件单元测试 每.cpp文件都应对应一个.h(.hpp)文件测试 |
#define保护ui |
1. #define PROJECT_PATH_FILE_H_ 防止.h文件被多重包含; |
Project sdk中.h文件sdk/src/abc.h,#define以下: 1 #ifndef SDK_SRC_ABC_H_ 2 #define SDK_SRC_ABC_H_ 3 ... 4 #endif // SDK_SRC_ABC_H_ |
前置声明 |
1. 使用前置声明尽可能减小文件中#include的数量; 2. 使用函数时,采用#include方式; 3. 使用类模版时,采用#include方式; 4. 使用普通类时,采用前置声明; 5. 数据成员为类自身的指针或引用时,采用前置声明; |
能够依赖声明,就不要依赖定义; |
|
内联函数 |
1. 不要内联超过10行的函数; 2. 析构函数应慎重对待; 3. 内联包含循环或switch语言的函数将得不偿失; 4. 虚函数和递归函数即便被声明为内联也不必定是内联函数; |
|
|
-inl.h函数 |
1. 复杂的内联函数定义,放在后缀名为-inl.h的头文件中; |
|
|
函数参数顺序 |
1. 函数参数顺序:输入参数在前,输出参数在后; |
1. 输入参数为传值或常数引用、常指针; 2. 输出参数为很是数指针、很是数引用; |
|
包含文件的名字和顺序 |
1. 包含.h文件次序:优先的.h文件、C库、C++库、其余库的.h、项目内的.h; 2. 项目内.h文件应按照项目源代码目录树结构排列,而且避免使用UNIX目录.(当前目录)和..(父目录); 3. 相同目录下.h文件按字母序排列; |
1. google-awe-project/src/base/logging.h应这样被包含: #include “base/logging.h”; 2. 某foo.cc(或foo.cpp)文件中包含.h文件次序: 1 #include “foo/public/foo.h” // 优先.cc或.cpp对应的头文件 2 #include <sys/types.h> // C库 3 #include <hash_map> // C++库 4 #include <foo/public/bar.h> // 项目内头文件 |
|
做用域 |
做用域 |
1. 在.cpp文件(不能在.h文件)中,使用不具名的命名空间; 2. 具名命名空间的名称基于项目或路径名称; 3. 不要使用using指示符,避免污染命名空间,可使用using; 4. 在.cpp文件、.h文件中的函数和类中,可使用using; 5. 在.cpp文件、.h文件中的函数和类中,可使用命名空间别名; 6. 不要使用inline namespace; |
1. 在.cpp文件中的不具名命名空间: 1 namespace 2 { 3 enum {UNUSED, EOF, ERROR}; // 无缩进 4 bool foo() {return EOF;} 5 } // namespace 2. 具名命名空间: 1 namespace mynamespace 2 { 3 class MyClass 4 { 5 public: 6 void foo(); 7 }; 8 } // namespace mynamespace |
嵌套类 |
1. 嵌套类不做为接口使用时,不要定义为public; 2. 嵌套类做为接口的一部分时,置于命名空间中; |
非接口嵌套类: 1 class Foo 2 { 3 private: 4 class Bar 5 { 6 }; 7 }; |
|
非成员函数、静态成员函数、全局函数 |
1. 使用命名空间中的非成员函数或静态成员函数,尽可能不使用全局函数; 2. 若肯定须要定义非成员函数,而且只在.cpp文件中使用它,可以使用不具名命名空间或static关联限定其做用域; |
|
|
局部变量 |
1. 将函数变量尽量置于最小做用域内,在声明变量时将其初始化; |
|
|
静态和全局变量 |
1. 禁止class类型的全局(静态)变量,若必定要使用,可单例模式; 2. 多线程代码中禁止很是数全局变量,不可以使用函数返回值初始化全局变量; 3. 全局字符串常量,使用C风格字符串,而不要使用STL字符串; 4. 大多数全局变量应该是类的静态数据成员,或当其只在.cpp文件中使用时,将其定义到不具名命名空间中,或者使用静态关联以限制变量的做用域; 5. 静态成员变量视做全局变量,不能是class类型; |
C风格字符串常量: 1 const char kFrogSays[] = “ribbet”; |
|
类 |
构造函数职责 |
1. 构造函数只进行那些没有实际意义的初始化; 2. 若是对象须要有意义的初始化,能够采用工厂函数或者Init()方法集中初始化; 3. 构造函数禁止调用虚函数; |
|
初始化 |
1. 若类中定义了成员变量,没有提供其余构造函数,须要定义一个默认构造函数; |
|
|
显式构造函数 |
1. 除非必要,单参数构造函数使用C++关键字explicit; |
1 explicit Foo(string name); |
|
拷贝构造函数 |
1. 仅在代码中须要拷贝一个类对象的时候使用拷贝构造函数,不须要拷贝时应使用DISALLOW_COPY_AND_ASSIGN; |
能够考虑在类的private中添加空的拷贝构造函数和赋值操做,而且只有声明,不进行定义; 1 #define DISALLOW_COPY_AND_ASSIGN(Type) \ 2 Type(const Type&); \ 3 void operator = (const Type&) 4 5 class Foo 6 { 7 public: 8 Foo(int f); 9 ~Foo(); 10 private: 11 DISALLOW_COPY_AND_ASSIGN(Foo); 12 }; |
|
结构体和类 |
1. 仅当只有数据时使用struct,其它状况使用class; 2. 对于functor和trait,可使用struct; 3. 类和结构体的成员变量使用不一样的命名规则(见下面的命名约定); |
|
|
继承 |
1. 全部继承必须为public继承,采用基类对象做为成员的方式替代私有继承; 2. 不要过多使用实现继承,更多使用组合; 3. 使析构函数为virtual,若是该类具备虚函数,其析构函数必定为虚函数; 4. 限定仅在子类访问的成员函数为protected,数据成员应始终为私有; 5. 重定义派生的虚函数时,在派生类中明确声明其为virtual; |
|
|
多继承 |
1. 只有当最多一个基类中含有实现,其余基类都是以Interface为后缀的纯接口类时才使用多继承; 2. 纯接口必须以Interface为后缀; |
|
|
接口 |
1. 知足纯接口要求时,类以Interface结尾; 2. 接口类必须声明虚析构函数,析构函数不能纯虚函数; |
知足纯接口类的要求: * 只有纯虚函数和静态函数(析构函数除外); * 没有非静态数据成员; * 没有定义任何构造函数,如有,须不含参数,且为protected; * 若是是子类,只能继承知足以上条件并以Interface为后缀的类; |
|
操做符重载 |
1. 通常不要重载操做符,若是须要的话,能够定义相似Equal()、CopyFrom()等函数; 2. STL容器中做为key要重载operator==或operator<,能够在声明容器的时候,建立相等判断和大小比较的仿函数类型; |
|
|
访问控制 |
1. 将类数据成员设为private,并提供相关存取函数; 2. 存取函数的定义通常内联在头文件中; |
定义变量m_foo及其取值函数foo()、赋值函数setFoo(); |
|
声明顺序 |
1. 类中定义次序:public:、protected:、private:; 2. 每一块中,声明次序为:typedef和enum、常量(static const数据成员)、构造函数、析构函数、成员函数(含静态成员函数)、数据成员(除static const数据成员); 3. 宏DISALLOW_COPY_AND_ASSIGN置于private:块以后,做为类的最后部分; 4. .cc文件中函数的定义顺序和声明次序一致; |
|
|
编写短小函数 |
1. 若是函数超过40行,能够考虑在不影响程序结构的状况下将其分割; |
|
|
其它C++特性 |
智能指针 |
1. 任何状况下禁止使用auto_ptr; |
|
引用参数 |
1. 全部按引用传递的参数必须为const引用; 2. 输入参数采用const引用,输出参数采用指针; 3. 输入参数能够是const指针,但不能够是non-const引用; |
|
|
函数重载 |
1. 仅在输入参数类型不一样、功能相同时使用重载函数; |
|
|
缺省参数 |
1. 禁止使用缺省参数; |
|
|
变长数组和alloca |
1. 禁止使用变长数组和alloca(); |
|
|
友元 |
1. 能够合理使用友元类及友元函数; |
|
|
异常 |
1. 禁止使用异常; |
|
|
运行时类型识别 |
1. 除单元测试外,禁止使用RTTI; |
|
|
类型转换 |
1. 使用C++风格而不要使用C风格类型转换; 2. 除单元测试外不要使用dynamic_cast; |
使用static_case <> ()等C++的类型转换; |
|
流 |
1. 除日志接口外,使用printf之类的代替流; |
最好选择printf + read/write; |
|
前置自增和自减 |
1. 对于迭代器和其余模板对象使用前缀形式自增和自减运算符; |
|
|
const使用 |
1. 在任何可使用的状况下使用const; |
|
|
整型 |
1. 使用断言声明变量为非负数,不要使用无符号型; |
|
|
64位下的可移植性 |
1. printf指定的一些类型在32位和64位系统上可移植性不是很好; 2. sizeof(void *) != sizeof(int),能够用intptr_t定义指针大小的整数; 3. 结构体字节对齐; 4. 建立64位常量时使用LL或ULL做为后缀; |
int64_t my_value = 0x123456LL; |
|
预处理宏 |
1. 慎用宏,尽量之内联函数、枚举和常量代替; 2. 在.h文件中,除了#define防止头文件重包含外,不要定义宏; |
|
|
0和NULL |
1. 整数用0,实数用0.0,指针用NULL,字符(串)用’\0’; |
|
|
sizeof |
1. 尽量用sizeof(varname)代替sizeof(type); |
|
|
Boost库 |
1. 只使用Boost中被承认的库: Compressed Pair:boost/compressed_pair.hpp; Pointer Container:boost/ptr_container,其中不包括ptr_array.hpp和serialization; |
|
|
命名约定 最重要是一致性 |
通用命名规则 |
1. 函数、变量、文件命名应具备描述性,不要过分缩写,类型和变量应是名词,函数名能够用“命令性”动词; 2. 除非放到项目外也很是明了,不然不要使用缩写; |
1. int num_completed_connections; 2. int num_dns_connections; 3. int error_count; // Good. int error_cnt; // Bad. |
文件命名 |
1. 文件名要所有小写,能够包含’_’或’-’,按项目约定来; 2. 源文件以.cc结尾,头文件以.h结尾;
|
可接受的文件命名: my_useful_class.cc my-useful-class.cc myusefulclass.cc |
|
类型命名 |
1. 类型命名每一个单词以大写字母开头,不包含下划线; |
1. 类型:类、结构体、类型定义(typedef)、枚举; 2. 如:MyExcitingClass、UrlTable; |
|
变量命名 |
1. 变量名一概小写,单词间如下划线相连,类的成员变量如下划线结尾; 2. 结构体数据成员能够和普通变量同样,不用像类的成员数据那样如下划线结尾; 3. 全局变量以g_做为前缀; |
1. 1 my_exciting_local_variable 2 my_exciting_member_variable_ 2. 1 struct UrlTablePoperties 2 { 3 sting name; 4 int num_entries; 5 }; |
|
常量命名 |
1. 在名称前加k; |
const int kDayInAWeek = 7; |
|
函数命名 |
1. 普通函数为大小写混合,存取函数则须要与变量名匹配; 2. 其它短小的内联函数可使用小写字母; |
1 MyExcitingMethod() 2 set_my_exciting_member_variable() |
|
命名空间 |
1. 命名空间所有为小写; |
|
|
枚举命名 |
1. 枚举值所有大写,单词间如下划线相连; |
|
|
宏命名 |
1. 若是要使用,其命名方式与枚举命名一致; |
|
|
代码注释 |
注释风格 |
1. 使用//或/* */,统一就好; |
|
文件注释 |
1. 在每个文件开头加入版权公告,而后是文件内容描述; |
|
|
类注释 |
1. 类的定义要附着描述类的功能和用法的注释; 2. 若是类的实例可被多线程访问,使用时务必文档说明; |
|
|
函数注释 |
1. 函数声明处注释描述函数功能,定义处描述函数实现; 2. 构造/析构函数前无需注释; |
1. 函数声明处注释的内容: * inputs及outputs; * 类成员函数:函数调用期间对象是否须要保持引用参数,是否会释放这些参数; * 若是函数分配了空间,须要由调用者释放; * 参数是否能够为NULL; * 是否存在函数使用的性能隐忧; * 若是函数是可重入的,其同步前提是什么; 2. 函数定义处定义的内容: 注释说明函数功能和实现要点; |
|
变量注释 |
1. 一般变量名自己足以很好说明变量用途,特定状况下,须要额外注释说明; |
|
|
实现注释 |
1. 对于实现代码中巧妙的、晦涩的、有趣的、重要的地方加以注释; 2. 相邻几行都有注释的,能够调整使//纵向对齐; |
|
|
TODO注释 |
1. 对那些临时的、短时间的解决方案,或已经够好但并不完美的代码使用TODO注释; |
// TODO(hanyp@126.com): change this. |
|
格式 |
行长度 |
1. 每一行代码字符数不超过80; |
|
空格 |
1. 只使用空格,每次缩进2个字符。设定编译器将Tab转为空格; |
|
|
函数声明和定义 |
1. 函数名、返回类型、参数尽量在同一行; 2. 若是函数为const的,const应与最后一个参数位于同一行; 3. 独立行的参数保持4个空格的缩进; |
1 ReturnType ClassName::FunctionName(Type ar_name1, Type par_name2) 2 { 3 DoSomething(); 4 } |
|
函数调用 |
1. 同函数声明和定义格式; |
|
|
条件语句 |
1. 不要再圆括号内加空格; |
1 if (condition) 2 { 3 ... 4 } 5 else 6 { 7 ... 8 } |
|
循环和选择语句 |
1. 类比条件语句; |
|
|
指针和引用表达式 |
1. 句点(.)或箭头(->)先后不要有空格,指针/地址操做符(*、&)后不要空格; 1. 在声明指针、引用变量或参数时,(*、&)与类型名紧挨; |
|
|
布尔表达式 |
1. 若是一个布尔表达式超过标准行宽,断行要统一; |
|
|
函数返回值 |
1. return表达式中不要使用圆括号; |
|
|
变量及数组初始化 |
1. 使用()格式; |
int x(3); |
|
预处理指令 |
1. 预处理指令不须要缩进; |
|
|
类格式 |
1. public、protected、private不须要缩进,函数及变量定义缩进2空格; |
|
|
初始化列表 |
1. 构造函数初始化列表放在同一行或按四格缩进并排几行; 2. ‘:’先后各空一格; |
|
|
命名空间格式 |
1. 命名空间内容不须要缩进,命名空间不添加额外缩进层次; |