[CPP] Coding Style


C++ Coding Style


C++很多强大的语言特性导致它的复杂,其复杂性会使得代码更容易出现bug、难于阅读和维护。

本Coding Style用来约束C++编程,使得代码在有效使用C++语言特性的同时易于管理【代码的一致性高于一切】。

参考《Google C++ Style Guide》


分类


标题


规则


备注(示例)


头文件

每个.cc文件都应对应一个.h文件


#define保护


1.  #define PROJECT_PATH_FILE_H_ 防止.h文件被多重包含;


1. 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文件中包含.h文件次序:

1 #include “foo/public/foo.h”
2 #include <sys/types.h>
3 #include <hash_map>
4 #include <foo/public/bar.h>


作用域


作用域


1. 在.cc文件(不能在.h文件)中,使用不具名的命名空间;

2. 具名命名空间的名称基于项目或路径名称;

3. 不要使用using指示符;

4. 在.cc文件、.h文件中的函数和类中,可以使用using;

5. 在.cc文件、.h文件中的函数和类中,可以使用命名空间别名;

6. 不要使用inline namespace;


1. 在.cc文件中不具名命名空间:

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. 非接口嵌套类:

1 class Foo
2 {
3 private:
4     class Bar
5     {
6     };
7 };


非成员函数、静态成员函数、全局函数


1. 使用命名空间中的非成员函数或静态成员函数,尽量不使用全局函数;

2. 若确定需要定义非成员函数,并且只在.cc文件中使用它,可使用不具名命名空间或static关联限定其作用域;


局部变量


1. 将函数变量尽可能置于最小作用域内,在声明变量时将其初始化;


静态和全局变量


1. 禁止class类型的全局(静态)变量,若一定要使用,可单例模式;

2. 多线程代码中禁止非常数全局变量,不可使用函数返回值初始化全局变量;

3. 全局字符串常量,使用C风格字符串,而不要使用STL字符串;

4. 大多数全局变量应该是类的静态数据成员,或当其只在.cc文件中使用时,将其定义到不具名命名空间中,或者使用静态关联以限制变量的作用域;

5. 静态成员变量视作全局变量,不能是class类型;


1. C风格字符串常量:

1 const char kFrogSays[] = “ribbet”;



构造函数职责


1. 构造函数只进行那些没有实际意义的初始化;

2. 如果对象需要有意义的初始化,可以采用工厂函数或者Init()方法集中初始化;

3. 构造函数禁止调用虚函数;


初始化


1. 若类中定义了成员变量,没有提供其他构造函数,需要定义一个默认构造函数;


显式构造函数


1. 单参数构造函数使用C++关键字explicit;


1.  explicit Foo(string name);


拷贝构造函数


1. 仅在代码中需要拷贝一个类对象的时候使用拷贝构造函数,不需要拷贝时应使用DISALLOW_COPY_AND_ASSIGN;


1. 可以考虑在类的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. 接口类必须声明虚析构函数,析构函数不能纯虚函数;


1. 满足纯接口类的要求:

* 只有纯虚函数和静态函数(析构函数除外);

* 没有非静态数据成员;

* 没有定义任何构造函数,若有,须不含参数,且为protected;

* 如果是子类,只能继承满足以上条件并以Interface为后缀的类;


操作符重载


1. 一般不要重载操作符,如果需要的话,可以定义类似Equal()、CopyFrom()等函数;

2. STL容器中作为key要重载operator==或operator<,可以在声明容器的时候,创建相等判断和大小比较的仿函数类型;


访问控制


1. 将类数据成员设为private,并提供相关存取函数;

2. 存取函数的定义一般内联在头文件中;


1. 定义变量foo_及其取值函数foo()、赋值函数set_foo();


声明顺序


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;


1. 使用static_case <> ()等C++的类型转换;



1. 除日志接口外,使用printf之类的代替流;


1. 最好选择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作为后缀;


1.  int64_t my_value = 0x123456LL;


预处理宏


1. 慎用宏,尽可能以内联函数、枚举和常量代替;

2. 在.h文件中,除了#define防止头文件重包含外,不要定义宏;


0NULL


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结尾;


1. 可接受的文件命名:

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;


1.  const int kDayInAWeek = 7;


函数命名


1. 普通函数为大小写混合,存取函数则需要与变量名匹配;

2. 其它短小的内联函数可以使用小写字母;


1.

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注释;


1.  // TODO([email protected]): change this.


格式


行长度


1. 每一行代码字符数不超过80;


空格


1. 只使用空格,每次缩进2个字符。设定编译器将Tab转为空格;


函数声明和定义


1. 函数名、返回类型、参数尽可能在同一行;

2. 如果函数为const的,const应与最后一个参数位于同一行;

3. 独立行的参数保持4个空格的缩进;


1.

1 ReturnType ClassName::FunctionName(Type ar_name1, Type par_name2)
2 {
3     DoSomething();
4 }


函数调用


1. 同函数声明和定义格式;


条件语句


1. 不要再圆括号内加空格;


1.

1 if (condition)
2 {
3     ...
4 }
5 else
6 {
7     ...
8 }


循环和选择语句


1. 类比条件语句;


指针和引用表达式


1. 句点(.)或箭头(->)前后不要有空格,指针/地址操作符(*、&)后不要空格;

1. 在声明指针、引用变量或参数时,(*、&)与类型名紧挨;


布尔表达式


1. 如果一个布尔表达式超过标准行宽,断行要统一;


函数返回值


1. return表达式中不要使用圆括号;


变量及数组初始化


1. 使用()格式;


1.  int x(3);


预处理指令


1. 预处理指令不需要缩进;


类格式


1. public、protected、private不需要缩进,函数及变量定义缩进2空格;


初始化列表


1. 构造函数初始化列表放在同一行或按四格缩进并排几行;

2. ‘:’前后各空一格;


命名空间格式


1. 命名空间内容不需要缩进,命名空间不添加额外缩进层次;

时间: 2024-08-24 14:18:24

[CPP] Coding Style的相关文章

Google&#39;s C++ coding style

v0.2 - Last updated November 8, 2013 源自 Google's C++ coding style rev. 3.274 目录 由 DocToc生成     头文件        #define用法        前向声明        内联函数        -inl.h文件        函数参数顺序        include的命名和顺序    作用域        命名空间            未命名空间            命名空间       

linux c coding style

Linux kernel coding style This is a short document describing the preferred coding style for the linux kernel. Coding style is very personal, and I won't _force_ my views on anybody, but this is what goes for anything that I have to be able to mainta

编程风格(Coding Style)要求

编程风格(Coding Style)要求2.1.1 文件(1) 每个模块(module)一般应存在于单独的源文件中,通常源文件名与所包含模块名相同.(2) 每个设计文件开头应包含如下注释内容:? 年份及公司名称.? 作者.? 文件名.? 所属项目.? 顶层模块.? 模块名称及其描述.? 修改纪录.2.1.2 大小写(1) 如无特别需要,模块名和信号名一律采用小写字母.(2) 为醒目起见,常数(`define定义)/参数(parameter定义)采用大写字母.2.1.3 标识符(1) 标识符采用传

Google C++ Coding Style:引用参数

Google C++ Coding Style定义 输入参数以值或者const引用形式传入,输出参数使用指针. 所有以引用形式输入参数必须加上const,即const T&的形式. 即如下形式: void Foo(const string &in, string *out); 在如下情况下, 可以使用const T*的形式: * 需要进行指针的判空 (即空指针是合理的). * 需要使用到输入参数的指针或引用形式. 为什么要使用const T&形式? 以值传入是最为安全的形式,因为它

Java coding style - Part one

Java coding style: 1. Factory method should be stateless. State normally refers to the member variables of class. Stateless, more precisely, it means immutable. Factory is just to create objects, and one call should not affect anothers, if it is muta

Verilog case coding style

1.一般情况下,综合器将case语句综合成多路选择器,但也可能综合成优先级译码器. 2.case语句中,如果条件列举不完全,将综合出不必要的锁存器. 综合器指令://synopsys parallel_case & //synopsys full_case 使用//synopsys parallel_case可以引导综合器生成多路选择器. 1 always @(cs_state) 2 begin 3 case(cs_state) // synopsys parallel_case 4 2'b00

Python&#39;s Coding Style

一个程序员良好的素养可以从他的代码风格里看出. Python官方的开发者指南,PEP8中,列举了Style Guide for Python Code. 摘录The Python's Tutorial中的依依列出. 1.用4空格缩进,而不是tab键. 2.使每行不超过79个字符,目的是小屏幕用户也能很好的阅读. 3.用空一行的方式去把函数,类,和函数中大的代码块分开. 4.如果可能的话,尽量把注释写在一行里. 5.Use docstrings.使用文档字符串.(Ps.这个可得利用好了) 6.在操

python coding style guide 的高速落地实践

python coding style guide 的高速落地实践 机器和人各有所长,如coding style检查这样的可自己主动化的工作理应交给机器去完毕,故发此文帮助你在几分钟内实现coding style的自己主动检查. 1.有哪些著名的Python Coding Style Guide PEP8 https://www.python.org/dev/peps/pep-0008/ 发明Python语言丰碑人物Guido van Rossum的亲自写的Coding Style, 知名度5颗

【九章算法免费公开课】从 strStr 谈面试技巧与 Coding Style

刷题到底刷到什么程度才够? 题目不会直接说不会么? 为什么题目都做出来还是老是挂? 觉得面试官总在为难你? 从来就搞不懂动态规划是什么? 如何正确的骑驴找马? 什么是正确的Coding Style? 面试中该与面试官如何沟通? 本周日,九章算法<算法班>金牌讲师-段誉 为您倾情奉献,同时提供实时在线问答环节,解答您最想知道的面试"内幕"! 讲座时间: 北京时间6月14日 09:30-11:30 (周日) 美西时间6月13日 18:30-20:30(周六) 报名链接: htt