[CPP] Coding Style
|
C++ Coding Style |
|||
|
C++很多强大的语言特性导致它的复杂,其复杂性会使得代码更容易出现bug、难于阅读和维护。 由于,本人有一点点代码洁癖,所以依照Google的C++编程规范《Google C++ Style Guide》,用来约束自己平时编程,使得代码在有效使用C++语言特性的同时易于管理。 |
|||
|
分类 |
标题 |
规则 |
备注(示例) |
|
头文件 每.cpp文件都应对应一个.h(.hpp)文件 |
#define保护 |
1. #define PROJECT_PATH_FILE_H_ 防止.h文件被多重包含; |
Project sdk中.h文件sdk/src/abc.h,#define如下: #ifndef 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文件次序: #include “foo/public/foo.h” // 优先.cc或.cpp对应的头文件 |
|
|
作用域 |
作用域 |
1. 在.cpp文件(不能在.h文件)中,使用不具名的命名空间; 2. 具名命名空间的名称基于项目或路径名称; 3. 不要使用using指示符,避免污染命名空间,可以使用using; 4. 在.cpp文件、.h文件中的函数和类中,可以使用using; 5. 在.cpp文件、.h文件中的函数和类中,可以使用命名空间别名; 6. 不要使用inline namespace; |
1. 在.cpp文件中的不具名命名空间: namespace 2. 具名命名空间: namespace mynamespace |
|
嵌套类 |
1. 嵌套类不作为接口使用时,不要定义为public; 2. 嵌套类作为接口的一部分时,置于命名空间中; |
非接口嵌套类: class Foo |
|
|
非成员函数、静态成员函数、全局函数 |
1. 使用命名空间中的非成员函数或静态成员函数,尽量不使用全局函数; 2. 若确定需要定义非成员函数,并且只在.cpp文件中使用它,可使用不具名命名空间或static关联限定其作用域; |
||
|
局部变量 |
1. 将函数变量尽可能置于最小作用域内,在声明变量时将其初始化; |
||
|
静态和全局变量 |
1. 禁止class类型的全局(静态)变量,若一定要使用,可单例模式; 2. 多线程代码中禁止非常数全局变量,不可使用函数返回值初始化全局变量; 3. 全局字符串常量,使用C风格字符串,而不要使用STL字符串; 4. 大多数全局变量应该是类的静态数据成员,或当其只在.cpp文件中使用时,将其定义到不具名命名空间中,或者使用静态关联以限制变量的作用域; 5. 静态成员变量视作全局变量,不能是class类型; |
C风格字符串常量: const char kFrogSays[] = “ribbet”; |
|
|
类 |
构造函数职责 |
1. 构造函数只进行那些没有实际意义的初始化; 2. 如果对象需要有意义的初始化,可以采用工厂函数或者Init()方法集中初始化; 3. 构造函数禁止调用虚函数; |
|
|
初始化 |
1. 若类中定义了成员变量,没有提供其他构造函数,需要定义一个默认构造函数; |
||
|
显式构造函数 |
1. 除非必要,单参数构造函数使用C++关键字explicit; |
explicit Foo(string name); |
|
|
拷贝构造函数 |
1. 仅在代码中需要拷贝一个类对象的时候使用拷贝构造函数,不需要拷贝时应使用DISALLOW_COPY_AND_ASSIGN; |
可以考虑在类的private中添加空的拷贝构造函数和赋值操作,并且只有声明,不进行定义; #define DISALLOW_COPY_AND_ASSIGN(Type) \ |
|
|
结构体和类 |
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. my_exciting_local_variable 2. struct UrlTablePoperties |
|
|
常量命名 |
1. 在名称前加k; |
const int kDayInAWeek = ; |
|
|
函数命名 |
1. 普通函数为大小写混合,存取函数则需要与变量名匹配; 2. 其它短小的内联函数可以使用小写字母; |
MyExcitingMethod() |
|
|
命名空间 |
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个空格的缩进; |
ReturnType ClassName::FunctionName(Type ar_name1, Type par_name2) |
|
|
函数调用 |
1. 同函数声明和定义格式; |
||
|
条件语句 |
1. 不要再圆括号内加空格; |
if (condition) |
|
|
循环和选择语句 |
1. 类比条件语句; |
||
|
指针和引用表达式 |
1. 句点(.)或箭头(->)前后不要有空格,指针/地址操作符(*、&)后不要空格; 1. 在声明指针、引用变量或参数时,(*、&)与类型名紧挨; |
||
|
布尔表达式 |
1. 如果一个布尔表达式超过标准行宽,断行要统一; |
||
|
函数返回值 |
1. return表达式中不要使用圆括号; |
||
|
变量及数组初始化 |
1. 使用()格式; |
int x(); |
|
|
预处理指令 |
1. 预处理指令不需要缩进; |
||
|
类格式 |
1. public、protected、private不需要缩进,函数及变量定义缩进2空格; |
||
|
初始化列表 |
1. 构造函数初始化列表放在同一行或按四格缩进并排几行; 2. ‘:’前后各空一格; |
||
|
命名空间格式 |
1. 命名空间内容不需要缩进,命名空间不添加额外缩进层次; |
||
[CPP] Coding Style的更多相关文章
- linux c coding style
Linux kernel coding style This is a short document describing the preferred coding style for the lin ...
- [中英对照]Linux kernel coding style | Linux内核编码风格
Linux kernel coding style | Linux内核编码风格 This is a short document describing the preferred coding sty ...
- Google's C++ coding style
v0.2 - Last updated November 8, 2013 源自 Google's C++ coding style rev. 3.274 目录 由 DocToc生成 头文件 ...
- Google C++ Coding Style 学习笔记
写在前面:最新公司马上就要开始开发一款视觉产品,工程量较大,且需要对客户提供可以二次开 发的SDK,整个项目用C++编写. 这就对代码质量提出了非常高的要求,同时,如何设计出优雅稳定的API也是相当大 ...
- 编程风格(Coding Style)要求
编程风格(Coding Style)要求2.1.1 文件(1) 每个模块(module)一般应存在于单独的源文件中,通常源文件名与所包含模块名相同.(2) 每个设计文件开头应包含如下注释内容:? 年份 ...
- Linux 内核Coding Style整理
转载:http://www.cnblogs.com/wang_yb/p/3532349.html 总结linux内核开发的coding style, 便于以后写代码时参考. 下面只是罗列一些规则, 具 ...
- (转帖) 有限狀態機FSM coding style整理 (SOC) (Verilog)
来源:http://www.codesoso.net/Record/101092_95120_21.html 来源:http://www.cnblogs.com/oomusou/archive/201 ...
- c coding style之学习篇
1. 使用do-while结构去避免潜在的内存泄漏问题. do { p1 = malloc(10); if (null == p1) { break; ...
- 谈谈Linux内核驱动的coding style【转】
转自:http://www.cnblogs.com/wwang/archive/2011/02/24/1960283.html 最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离 ...
随机推荐
- python 终端模拟模块 pexpect
简单介绍pexpect是 Don Libes 的 Expect 语言的一个 Python 实现,是一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的 Python 模块 ...
- 计蒜客 UCloud 的安全秘钥(随机化+Hash)
题目链接 UCloud 的安全秘钥 对于简单的版本,我们直接枚举每个子序列,然后sort一下判断是否完全一样即可. #include <bits/stdc++.h> using names ...
- 洛谷—— P1342 请柬
https://www.luogu.org/problemnew/show/1342 题目描述 在电视时代,没有多少人观看戏剧表演.Malidinesia古董喜剧演员意识到这一事实,他们想宣传剧院,尤 ...
- 洛谷——P1187 3D模型
P1187 3D模型 题目描述 一座城市建立在规则的n×m网格上,并且网格均由1×1正方形构成.在每个网格上都可以有一个建筑,建筑由若干个1×1×1的立方体搭建而成(也就是所有建筑的底部都在同一平面上 ...
- win10下ubuntu虚拟机互传文件
前言 用过虚拟机的都知道在向linux传文件的时候总是会遇到各种问题 安装虚拟机的增强工具不好用,反正就是各种麻烦各种麻烦 准备-------方案一 使用专门的xshell可以直接链接到虚拟机,同时配 ...
- MySQL中数据类型(char(n)、varchar(n)、nchar(n)、nvarchar(n)的区别)(转)
一.第一种 char(n)和varchar(n)的区别: 在这里我们可以清楚的看到他们表面的区别就是前面是否有var,在这里解释一下var是什么意思,var代表“可变的”的意思 下面看个例子: )// ...
- linux 用户管理命令学习
groupadd www-data 添加组 useradd phpcomposer -g www-data 添加用户并加入组中 passwd phpcomposer 添加密码 usermod -g p ...
- GridView数据绑定控件的模版列时设置显示的格式
形式 语法 结果 数字 {0:N2} 12.36 数字 {0:N0} 13 货币 {0:c2} $12.36 货币 {0:c4} $12.3656 货币 "¥{0:N2}&q ...
- 【Lintcode】二叉树的最大深度 - 比较简单,用递归比较好,不递归也能做,比较麻烦
给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的距离. 您在真实的面试中是否遇到过这个题? Yes 样例 给出一棵如下的二叉树: 1 / \ 2 3 / \ 4 5 这个二叉树的 ...
- TI C66x DSP 四种内存保护问题 -之- CPU訪问corePac内部资源时的内存保护问题
CPU訪问corePac内部资源(L1.L2)时的内存保护(通过设置内存的訪问权限实现)等问题请參考以下两个blog.已经叙述的非常具体. "TI C66x DSP 系统events及其应用 ...