个人进行C++
开发时会遵守的规范。参考了Google C++ Style Guide.
1. 头文件
1.1 #define保护
所有头文件都使用#define
来保护,防止头文件被重复包含。
#ifndef <PROJECT>_<PATH>_<FILE>_H_
#define <PROJECT>_<PATH>_<FILE>_H_
#endif //<PROJECT>_<PATH>_<FILE>_H_
1.3 #include路径及顺序
使用完整的项目路径,而不是(或少)使用.
和..
定位文件。
如果某个.cpp
文件主要是为了实现.h
文件中定义的功能,则优先包含该.h
文件。
然后依次按照以下顺序包含。
- C语言标准库及系统文件
- C++语言标准库文件
- 第三方库的头文件
- 本项目的头文件
2. 命名空间
一个项目内,尽量所有类、普通函数都用命名空间包裹。
命名空间全部顶格写,内部声明或定义的类、函数也要顶格写。
namespace ic {
namespace util {
class Decoder {
};
} // namespace util
} // namespace ic
3. 静态变量和全局变量
尽量不用全局变量,或者以Singleton
单例模式替代,手动控制全局变量的初始化顺序。
// init.cpp
Singleton<Foo>::Instance(); // 初始化
// cleanup.cpp
Singleton<Foo>::DesInstance(); // 析构
// main.cpp
auto foo = Singleton<Foo>::GetInstance(); // 获取全局访问点
foo->DoSomething();
4. 类
4.1 结构体 or 类
只有数据成员时使用struct
,否则使用class
。
4.2 声明顺序
相似的声明放在一起,从上到下依次为 public
, protected
, private
。
4.3 const
在任何可能的情况下都要使用const
!
在声明的变量或参数前加上关键字const
用于指明变量值不可被篡改
为类中的函数加上const
限定符表明该函数不会修改类成员变量的状态。
5. 函数
- 输入参数:传
值
或者const引用
。如果输入值可能为空,也可以考虑const指针
。 - 输出参数:
指针
。
6. 命名约定
6.1 文件命名
文件夹、文件名称全部小写,可以使用下划线(_
)。C++源文件使用.cpp
结尾。文件名称尽量不要与系统默认包含路径的文件重名。
geometry_point.h
geometry_point.cpp
6.2 类型命名
类型名称每个首字母都大写,不包含下划线,即大驼峰命名方式。
class Manager { };
class StudentInfo { };
6.3 变量命名
一律小写,单词间使用下划线连接。类(class
)成员变量以下划线结尾,结构体(struct
)不需要。
// 普通变量
int access_count;
size_t file_size;
size_t filesize;
// 结构体成员变量
struct Foo {
int access_count;
size_t file_size;
};
// 类成员变量
class Foo {
public:
private:
int access_count_ = 0;
size_t file_size_ = 0;
};
6.4 常量
以k
开头。
const int kTotalCount = 32;
6.5 (全局)静态变量
以s_
开头。
static std::string s_buffer;
6.6 全局变量
以g_
开头。
// main.cpp
#include <iostream>
int g_count = 0;
int main() {
// ...
return 0;
}
6.7 函数命名
一般情况
每个首字母大写(大驼峰命名方式),对于首字母缩写的单词, 更倾向于将它们视作一个单词进行首字母大写。
void Start();
void Stop();
int GenerateCode();
std::string GetFileName();
类的取值和设值成员函数
get_
或set_
开头,后面接成员变量名称。
class Foo {
public:
bool Init();
void DoSomething();
std::string GetDns() const; // not good: GetDNS
int get_count() const { return count_; }
void set_count(int c) { count_ = c; }
private:
int count_ = 0;
};
全局辅助函数
必须在作用域中包裹,函数名称全小写,用下划线连接。
// helper.h
namespace util {
namespace io {
bool write_binary(const std::string& filename, const std::string& content);
bool read_binary(const std::string& filename, std::string* content);
} // namespace io
} // namespace util
6.8 宏
字母全部大写,用下划线分割单词。
#define CHECK() ...
#define CHECK_NUMBER(num) ...
7. 注释
就个人而言,尽量采用 /* */
的风格注释,尤其是注释中出现汉字的时候。
8. 代码风格
8.1 行长度
尽量不超过120
,最长一定不超过140
。
8.2 文件编码
统一 UTF-8
编码。Linux下默认都是UTF-8编码,Windows下使用Visual Studio编程时文件要手动保存为UTF-8编码(或者安装插件自动编码为UTF-8),同时在项目属性->C/CPP->命令行
中添加/utf-8
选项。
8.3 缩进
一律使用4个空格,而非制表符。
8.4 函数
大括号与函数签名在同一行。如果参数过长而分为多行,大括号需要另起一行。
void Start() {
// ...
}
void LongParameterList(int param1, int param2, int param3,
int param4, int param5)
{
// ...
}
void VeryVeryVeryVeryVeryVeryVeryVeryLongFunctionName(
int param1,
int param2,
int param3)
{
// ...
}
8.5 if / else
if
和else if
和else
都另起一行。即使只有一句语句,也要用大括号。
if (x > 100) {
}
else if (x > 10) {
// ...
}
else {
// ...
}
8.6 指针/引用定义
*
紧跟类型名称,与指针变量名称空一格。定义时必须指向某个地址,或者赋值为空指针nullptr
。
int value = 99;
int* ptr1 = &value; // ok
int* ptr2 = nullptr; // ok
int* ptr3; // bad!
int& val = value; // ok
8.7 命名空间
不能增加缩进层次!
namespace foo {
std::string get_value() { /* 顶格写,不能缩进 */
// ...
}
} // namespace foo