170. C++ 编码规范

C++命名

通用命名

驼峰风格(CamelCase) 大小写字母混用,单词连在一起,不同单词间通过单词首字母大写来分开。 按连接后的首字母是否大写,又分: 大驼峰(UperCamelCase)和小驼峰(lowerCamelCase)

类型 命名风格
类类型,结构体类型,枚举类型,联合体类型等类型定义, 作用域名称 大驼峰
函数(包括全局函数,作用域函数,成员函数) 小驼峰
全局变量(包括全局和命名空间域下的变量,类静态变量),局部变量,函数参数,类、结构体和联合体中的成员变量 小驼峰
宏,常量(const),枚举值,goto 标签 全大写,下划线分割

注意: 上表中常量是指全局作用域、namespace域、类的静态成员域下,以 const或constexpr 修饰的基本数据类型、枚举、字符串类型的变量,不包括数组和其他类型变量。 上表中变量是指除常量定义以外的其他变量,均使用小驼峰风格。

文件命名

建议2.2.1 C++文件以.cpp结尾,头文件以.h结尾

我们推荐使用.h作为头文件的后缀,这样头文件可以直接兼容C和C++。 我们推荐使用.cpp作为实现文件的后缀,这样可以直接区分C++代码,而不是C代码。

目前业界还有一些其他的后缀的表示方法:

  • 头文件: .hh, .hpp, .hxx
  • cpp文件:.cc, .cxx, .C

如果当前项目组使用了某种特定的后缀,那么可以继续使用,但是请保持风格统一。 但是对于本文档,我们默认使用.h和.cpp作为后缀。

建议2.2.2 C++文件名和类名保持一致

C++的头文件和cpp文件名和类名保持一致,使用下划线小写风格。

如果有一个类叫DatabaseConnection,那么对应的文件名:

  • database_connection.h
  • database_connection.cpp

结构体,命名空间,枚举等定义的文件名类似。

函数命名

函数命名统一使用小驼峰风格,一般采用动词或者动宾结构。

1
2
3
4
5
6
7
8
9
10
11
class List {
public:
void addElement(const Element& element);
Element getElement(const unsigned int index) const;
bool isEmpty() const;
};

namespace Utils {
void deleteUser();
}

类型命名

类型命名采用大驼峰命名风格。 所有类型命名——类、结构体、联合体、类型定义(typedef)、枚举——使用相同约定,例如:

1
2
3
4
5
6
7
8
9
10
11
// classes, structs and unions
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...
union Packet { ...

// typedefs
typedef std::map<std::string, UrlTableProperties*> PropertiesMap;

// enums
enum UrlTableErrors { ...

对于命名空间的命名,建议使用大驼峰:

1
2
3
4
5
6
7
8
// namespace
namespace OsUtils {

namespace FileUtils {

}

}

建议2.4.1 避免滥用 typedef或者#define 对基本类型起别名

除有明确的必要性,否则不要用 typedef/#define 对基本数据类型进行重定义。 优先使用<cstdint>头文件中的基本类型:

有符号类型 无符号类型 描述
int8_t uint8_t 宽度恰为8的有/无符号整数类型
int16_t uint16_t 宽度恰为16的有/无符号整数类型
int32_t uint32_t 宽度恰为32的有/无符号整数类型
int64_t uint64_t 宽度恰为64的有/无符号整数类型
intptr_t uintptr_t 足以保存指针的有/无符号整数类型

变量命名

通用变量命名采用小驼峰,包括全局变量,函数形参,局部变量,成员变量。

1
2
3
4
5
6
// Good: 推荐此风格
std::string tableName;
// Bad: 禁止此风格
std::string tablename;
// Good: 只有一个单词时,小驼峰为全小写
std::string path;

规则2.5.1 全局变量应增加 ‘g_’ 前缀,静态变量命名不需要加特殊前缀

全局变量是应当尽量少使用的,使用时应特别注意,所以加上前缀用于视觉上的突出,促使开发人员对这些变量的使用更加小心。

  • 全局静态变量命名与全局变量相同。
  • 函数内的静态变量命名与普通局部变量相同。
  • 类的静态成员变量和普通成员变量相同。
1
2
3
4
5
6
int g_activeConnectCount;
void Func()
{
static int packetCount = 0;
...
}

规则2.5.2 类的成员变量命名以小驼峰加后下划线组成

1
2
3
4
5
class Foo {
private:
// 添加_后缀,类似于K&R命名风格
std::string fileName_;
};

对于struct/union的成员变量,仍采用小驼峰不加后缀的命名方式,与局部变量命名风格一致。

宏、常量、枚举命名

宏、枚举值采用全大写,下划线连接的格式。 全局作用域内,有名和匿名namespace内的 const 常量,类的静态成员常量,全大写,下划线连接;函数局部 const 常量和类的普通const成员变量,使用小驼峰命名风格。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 仅对宏命名举例,并不推荐用宏实现此类功能
#define MAX(a, b) (((a) < (b)) ? (b) : (a))
// 注意,枚举类型名用大驼峰,其下面的取值是全大写,下划线相连
enum TintColor {
RED,
DARK_RED,
GREEN,
LIGHT_GREEN
};

int Func(...)
{
// 函数局部常量
const unsigned int bufferSize = 100;
char *p = new char[bufferSize];
...
}

namespace Utils {
// 全局常量
const unsigned int DEFAULT_FILE_SIZE_KB = 200;
}

注释

  • 单行注释都放在上一行