C/C++ 规范
引言:本笔记整理了 Google C++ Style Guide 的关键规范,旨在提高代码可读性、可维护性和团队协作效率。
摘要:笔记涵盖头文件、作用域、命名空间、类、函数、命名、注释和格式等方面的规范,并提供示例和常见错误总结。
关键词:C++ 规范,代码风格,Google Style Guide
关联笔记:[[Python 规范]]
1. 头文件规范(Headers)
引言:头文件是 C++ 代码组织的重要组成部分,合理的头文件规范可以减少编译依赖,提高编译速度。
摘要:本节介绍头文件的基本规则、包含顺序、循环依赖处理和文件扩展名规范。
关键词:头文件,include guard,前向声明
关联笔记:无
1.1. 头文件基本规则
引言:每个 .h
/ .hpp
文件应只包含它本身需要的声明,避免依赖过多其他头文件。
摘要:使用 包含保护(Include Guards)或 #pragma once
防止重复包含。.cc
/ .cpp
文件只包含它自己对应的头文件和必要的依赖。
关键词:头文件,包含保护,依赖
示例
✅ 推荐:
// foo.h
#ifndef PROJECT_FOO_H_
#define PROJECT_FOO_H_
class Foo {
public:
void DoSomething();
};
#endif // PROJECT_FOO_H_
或使用 #pragma once
:
#pragma once
class Foo {
public:
void DoSomething();
};
❌ 不推荐:
// foo.h
#include "bar.h" // 不必要的头文件依赖
class Foo { ... };
常见错误总结
- 头文件缺少保护(Include Guards 或
#pragma once
)
- 包含顺序混乱,导致编译警告或隐藏依赖
- 直接包含循环依赖头文件而非使用前向声明
- 不区分项目头文件与第三方库头文件,容易引入依赖混乱
- 混用
.h
和 .hpp
、.cc
与 .cpp
扩展名
1.2. 包含顺序
引言:合理的包含顺序可以减少编译错误,提高代码可读性。
摘要:介绍头文件的包含顺序:对应头文件、C 标准库、C++ 标准库、第三方库、本项目其他头文件。
关键词:头文件,包含顺序,标准库
示例
✅ 推荐:
#include "foo.h" // 对应头文件
#include <cstdlib> // C 标准库
#include <vector> // C++ 标准库
#include "gtest/gtest.h" // 第三方库
#include "project/bar.h" // 项目内部头文件
❌ 不推荐:
#include <vector>
#include "bar.h"
#include "foo.h"
常见错误总结
- 头文件缺少保护(Include Guards 或
#pragma once
)
- 包含顺序混乱,导致编译警告或隐藏依赖
- 直接包含循环依赖头文件而非使用前向声明
- 不区分项目头文件与第三方库头文件,容易引入依赖混乱
- 混用
.h
和 .hpp
、.cc
与 .cpp
扩展名
1.3. 避免头文件循环依赖
引言:循环依赖会导致编译错误,影响代码可维护性。
摘要:介绍使用 前向声明 而不是包含完整头文件来避免循环依赖。
关键词:头文件,循环依赖,前向声明
示例
✅ 推荐:
// a.h
class B; // 前向声明
class A {
B* b_; // 只用指针,不需要完整类型
};
❌ 不推荐:
// a.h
#include "b.h" // 会导致循环依赖
class A {
B* b_;
};
常见错误总结
- 头文件缺少保护(Include Guards 或
#pragma once
)
- 包含顺序混乱,导致编译警告或隐藏依赖
- 直接包含循环依赖头文件而非使用前向声明
- 不区分项目头文件与第三方库头文件,容易引入依赖混乱
- 混用
.h
和 .hpp
、.cc
与 .cpp
扩展名
1.4. 文件扩展名
引言:统一的文件扩展名可以提高代码可读性,方便管理。
摘要:介绍头文件和源文件的扩展名规范:头文件 .h
或 .hpp
,源文件 .cc
/ .cpp
。
关键词:文件扩展名,头文件,源文件
示例
✅ 推荐:
foo.h // 头文件
foo.cc // 源文件
❌ 不推荐:
foo.hpp
foo.cpp // 项目中混用扩展名
1.4.1. 常见错误总结
- 头文件缺少保护(Include Guards 或
#pragma once
)
- 包含顺序混乱,导致编译警告或隐藏依赖
- 直接包含循环依赖头文件而非使用前向声明
- 不区分项目头文件与第三方库头文件,容易引入依赖混乱
- 混用
.h
和 .hpp
、.cc
与 .cpp
扩展名
2. 作用域 & 命名空间规范
引言:作用域和命名空间是 C++ 代码组织的重要组成部分,合理的规范可以避免命名冲突,提高代码可读性。
摘要:本节介绍命名空间的使用、嵌套、局部作用域和静态与匿名命名空间规范。
关键词:命名空间,作用域,静态,匿名
2.1. 使用命名空间
引言:避免在头文件中使用 using namespace
,防止污染全局命名空间。
摘要:在 .cpp
文件中可以局部使用 using
,保持可读性。尽量在命名空间内部定义类和函数,避免全局作用域。
关键词:命名空间,using,全局作用域
示例
✅ 推荐:
// foo.h
namespace project {
class Foo {
public:
void DoSomething();
};
} // namespace project
❌ 不推荐:
// foo.h
using namespace std; // 污染全局命名空间
class Foo { ... };
常见错误总结
- 在头文件中使用
using namespace
- 命名空间层级过深,导致可读性差
- 局部变量作用域过大,易引入逻辑错误
- 忘记在
.cpp
文件中限制内部符号(static / 匿名命名空间)
2.2. 命名空间嵌套
引言:尽量减少嵌套层级,避免过深导致可读性下降。
摘要:对于大项目,可以使用多级命名空间,但注意简洁。
关键词:命名空间,嵌套,可读性
示例
✅ 推荐:
namespace project {
namespace module {
class Foo { ... };
} // namespace module
} // namespace project
❌ 不推荐:
namespace project {
namespace module {
namespace submodule {
namespace internal {
class Foo { ... };
} } } } // 四层嵌套,过深
常见错误总结
- 在头文件中使用
using namespace
- 命名空间层级过深,导致可读性差
- 局部变量作用域过大,易引入逻辑错误
- 忘记在
.cpp
文件中限制内部符号(static / 匿名命名空间)
2.3. 局部作用域
引言:变量应尽量缩小作用域,避免全局或类成员占用不必要的范围。
摘要:循环或临时变量应在最小作用域定义。
关键词:作用域,局部变量,循环
示例
✅ 推荐:
void ProcessItems() {
for (int i = 0; i < items.size(); ++i) {
int temp = Compute(items[i]);
DoSomething(temp);
}
}
❌ 不推荐:
int temp; // 定义在函数开头,占用过大作用域
void ProcessItems() {
for (int i = 0; i < items.size(); ++i) {
temp = Compute(items[i]);
DoSomething(temp);
}
}
常见错误总结
- 在头文件中使用
using namespace
- 命名空间层级过深,导致可读性差
- 局部变量作用域过大,易引入逻辑错误
- 忘记在
.cpp
文件中限制内部符号(static / 匿名命名空间)
2.4. 静态与匿名命名空间
引言:在 .cpp
文件中使用 static
或匿名命名空间限定内部链接,避免全局符号冲突。
摘要:介绍使用 static
或匿名命名空间限定内部链接。
关键词:静态,匿名命名空间,内部链接
示例
✅ 推荐:
namespace {
int helper_function(int x) {
return x * 2;
}
} // 匿名命名空间
❌ 不推荐:
int helper_function(int x) { // 全局作用域,可能冲突
return x * 2;
}
常见错误总结
- 在头文件中使用
using namespace
- 命名空间层级过深,导致可读性差
- 局部变量作用域过大,易引入逻辑错误
- 忘记在
.cpp
文件中限制内部符号(static / 匿名命名空间)
3. 类与函数规范
引言:类和函数是 C++ 代码的基本组成部分,合理的规范可以提高代码可读性、可维护性和可重用性。
摘要:本节介绍类的设计、构造函数与析构函数、拷贝与赋值、函数命名、参数、长度和返回值规范。
关键词:类,函数,构造函数,析构函数,拷贝,赋值
3.1. 类规范
引言:类的设计应该遵循单一职责原则,保持小而清晰。
摘要:类名使用 驼峰式命名(CapWords),所有成员尽量设置为私有(private),通过 public 方法访问。
关键词:类,驼峰式命名,私有成员
示例
✅ 推荐:
class FooManager {
public:
FooManager();
void Process();
private:
int count_;
};
❌ 不推荐:
class foo_manager { // 小写,不符合驼峰式
public:
int count; // 成员直接暴露
};
常见错误总结
- 成员变量暴露 public,破坏封装
- 构造函数逻辑过复杂
- 拷贝/赋值操作未处理,易引发错误
- 类过大,职责不单一
3.2. 构造函数与析构函数
引言:构造函数和析构函数是类的重要组成部分,合理的规范可以避免内存泄漏和资源管理问题。
摘要:构造函数初始化列表优先使用,对需要析构的类,声明虚析构函数,避免复杂逻辑放在构造函数中。
关键词:构造函数,析构函数,初始化列表,虚析构函数
示例
✅ 推荐:
class Foo {
public:
Foo() : count_(0) {} // 初始化列表
virtual ~Foo() {} // 虚析构函数
private:
int count_;
};
❌ 不推荐:
class Foo {
public:
Foo() { count_ = 0; DoSomething(); } // 构造函数逻辑复杂
~Foo() {}
private:
int count_;
};
常见错误总结
- 成员变量暴露 public,破坏封装
- 构造函数逻辑过复杂
- 拷贝/赋值操作未处理,易引发错误
- 类过大,职责不单一
3.3. 拷贝与赋值
引言:拷贝和赋值操作是类的重要组成部分,合理的规范可以避免内存泄漏和资源管理问题。
摘要:如果不需要拷贝,显式删除拷贝构造和赋值操作,优先使用 默认 构造和移动语义。
关键词:拷贝,赋值,默认构造,移动语义
示例
✅ 推荐:
class Foo {
public:
Foo() = default;
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
};
❌ 不推荐:
class Foo {
public:
Foo() {}
// 没有删除拷贝构造和赋值,可能误用
};
常见错误总结
- 成员变量暴露 public,破坏封装
- 构造函数逻辑过复杂
- 拷贝/赋值操作未处理,易引发错误
- 类过大,职责不单一
3.4. 函数规范
引言:函数是 C++ 代码的基本组成部分,合理的规范可以提高代码可读性、可维护性和可重用性。
摘要:本节介绍函数命名、参数、长度和返回值规范。
关键词:函数,命名,参数,长度,返回值
3.4.1. 命名
引言:统一的函数命名规范可以提高代码可读性,减少理解成本。
摘要:函数名使用 小写下划线分隔(如 ComputeValue
→ compute_value
),访问器函数(getter/setter)使用 set_
/ get_
前缀。
关键词:函数,命名,小写下划线分隔,getter,setter
示例
✅ 推荐:
class Foo {
public:
int get_count() const { return count_; }
void set_count(int value) { count_ = value; }
private:
int count_;
};
❌ 不推荐:
class Foo {
public:
int Count() { return count_; } // 首字母大写,不推荐
};
3.4.2. 参数
引言:合理的函数参数规范可以提高代码可读性,减少不必要的拷贝。
摘要:函数参数尽量使用 const 引用 避免不必要拷贝,默认参数应放在参数列表末尾。
关键词:函数,参数,const 引用,默认参数
示例
✅ 推荐:
void Process(const std::vector<int>& items, int multiplier = 1);
❌ 不推荐:
void Process(int multiplier = 1, std::vector<int> items); // 默认参数位置错误
3.4.3. 函数长度
引言:函数长度应尽量保持简短,提高代码可读性。
摘要:尽量保持函数简短,最好 <40 行,避免多重嵌套,将重复逻辑提取成辅助函数。
关键词:函数,长度,简短,嵌套,辅助函数
示例
✅ 推荐:
void ProcessItems(const std::vector<int>& items) {
for (int item : items) {
HandleItem(item);
}
}
void HandleItem(int item) {
// 处理单个 item
}
❌ 不推荐:
void ProcessItems(const std::vector<int>& items) {
for (int i = 0; i < items.size(); ++i) {
if (items[i] > 0) {
// 多层嵌套,函数过长
}
}
}
3.4.4. 返回值
引言:合理的函数返回值规范可以避免悬空引用和内存泄漏。
摘要:返回值尽量使用 值语义 或 const 引用,不返回局部指针/引用,避免悬空引用。
关键词:函数,返回值,值语义,const 引用,悬空引用
示例
✅ 推荐:
std::string GetName() const { return name_; } // 值语义
const std::string& GetNameRef() const { return name_; } // const 引用
❌ 不推荐:
std::string& GetName() { return local_name; } // 返回局部变量引用
常见错误总结(函数)
- 函数名不规范,首字母大写或不清晰
- 参数顺序或默认参数不合理
- 函数过长,嵌套过多
- 返回局部指针/引用,导致悬空引用
4. 命名 & 注释规范
引言:良好的命名和注释规范可以提高代码可读性,方便理解和维护。
摘要:本节介绍类名、函数名、变量名、常量与宏的命名规范,以及文件注释、函数注释、行内注释和 TODO 注释的规范。
关键词:命名,注释,驼峰式,下划线
4.1. 命名规范
引言:统一的命名规范可以提高代码可读性,减少理解成本。
摘要:类名使用 驼峰式命名(CapWords),函数名使用 小写下划线分隔(snake_case),变量名使用 小写下划线分隔,成员变量末尾加下划线 _
,常量全大写,单词用下划线分隔,尽量避免使用宏。
关键词:命名,驼峰式,下划线,常量,宏
示例
✅ 推荐:
class FooManager {
// 类管理 Foo 对象
};
void set_count(int value);
int get_count() const;
int count_;
std::string file_name_;
const int MAX_COUNT = 100;
❌ 不推荐:
class foo_manager { // 小写,不符合驼峰式
};
void SetCount(int value); // 首字母大写
int Count; // 大写,容易混淆
std::string filename; // 不加下划线,成员和局部可能混淆
#define MAXCOUNT 100 // 宏,不推荐
常见错误总结
- 类名不使用驼峰式
- 成员变量不加下划线或与局部变量混淆
- 函数名首字母大写或命名不明确
- 使用宏定义常量
4.2. 注释规范
引言:良好的注释规范可以提高代码可读性,方便理解和维护。
摘要:每个文件开头应有文件注释,说明文件功能和作者(可选),函数前加简要描述,参数和返回值说明可选,但推荐,仅在必要时使用行内注释,使用 //
,保持简洁,TODO 注释格式:// TODO(username): 描述
,说明任务内容和责任人。
关键词:注释,文件注释,函数注释,行内注释,TODO 注释
示例
✅ 推荐:
// foo.cc
// 实现 FooManager 类功能
// 设置计数值
// @param value 新计数值
void set_count(int value);
int x = 0; // 初始化计数器
// TODO(jian): 优化排序算法
❌ 不推荐:
// 没有文件注释
void set_count(int value); // 没有注释
int x = 0; // 计数器初始化赋值为0
// TODO: 优化排序算法 // 没有责任人
常见错误总结
- 文件没有注释
- 函数缺少描述
- 行内注释过长或无意义
- TODO 注释缺少责任人
5. 格式规范
引言:统一的格式规范可以提高代码可读性,减少视觉疲劳。
摘要:本节介绍缩进、行长度、空行、空格使用、大括号位置和多行表达式的格式规范。
关键词:格式,缩进,行长度,空行,空格,大括号
5.1. 缩进
引言:使用空格缩进,禁止使用 Tab。
摘要:使用 2 或 4 个空格缩进(Google 推荐 2 或 4 空格,保持项目统一),禁止使用 Tab。
关键词:缩进,空格,Tab
示例
✅ 推荐:
void Foo() {
int x = 0;
if (x > 0) {
DoSomething();
}
}
❌ 不推荐:
void Foo() {
int x = 0; // 使用 Tab
if (x > 0) {
DoSomething();
}
}
常见错误总结
- 使用 Tab 而不是空格
- 行长度超过 80 字符
- 顶层函数/类之间空行不正确
- 运算符、括号、逗号空格使用不一致
- 大括号位置混乱,函数和控制语句不统一
- 多行表达式对齐差,可读性差
5.2. 行长度
引言:单行代码尽量不超过 80 个字符,提高代码可读性。
摘要:单行代码尽量 不超过 80 个字符,注释或字符串允许到 100 个字符。
关键词:行长度,可读性,字符
示例
✅ 推荐:
void ProcessItems(const std::vector<int>& items,
int multiplier = 1);
❌ 不推荐:
void ProcessItems(const std::vector<int>& items, int multiplier = 1, bool flag = true, std::string name = "default");
常见错误总结
- 使用 Tab 而不是空格
- 行长度超过 80 字符
- 顶层函数/类之间空行不正确
- 运算符、括号、逗号空格使用不一致
- 大括号位置混乱,函数和控制语句不统一
- 多行表达式对齐差,可读性差
5.3. 空行
引言:合理的空行可以提高代码可读性,分隔代码块。
摘要:顶层函数和类定义之间:两个空行,类成员函数之间:一个空行。
关键词:空行,代码块,可读性
示例
✅ 推荐:
class Foo {
public:
void DoSomething();
private:
int count_;
};
void GlobalFunction() {
// ...
}
❌ 不推荐:
class Foo {
public:
void DoSomething();
private:
int count_;
}
void GlobalFunction() {
// ...
}
常见错误总结
- 使用 Tab 而不是空格
- 行长度超过 80 字符
- 顶层函数/类之间空行不正确
- 运算符、括号、逗号空格使用不一致
- 大括号位置混乱,函数和控制语句不统一
- 多行表达式对齐差,可读性差
5.4. 空格使用
引言:合理的空格使用可以提高代码可读性,减少视觉疲劳。
摘要:运算符两边加空格(a + b
),函数调用、下标操作不要在括号内加空格,逗号后面加空格。
关键词:空格,运算符,函数调用,下标操作,逗号
示例
✅ 推荐:
int sum = a + b;
foo(x, y);
arr[i] = value;
❌ 不推荐:
int sum=a+b;
foo( x ,y );
arr [i] = value;
常见错误总结
- 使用 Tab 而不是空格
- 行长度超过 80 字符
- 顶层函数/类之间空行不正确
- 运算符、括号、逗号空格使用不一致
- 大括号位置混乱,函数和控制语句不统一
- 多行表达式对齐差,可读性差
5.5. 大括号位置
引言:统一的大括号位置可以提高代码可读性,减少视觉疲劳。
摘要:函数和类的左大括号 新起一行,控制语句的左大括号 同行。
关键词:大括号,函数,类,控制语句
示例
✅ 推荐:
// 函数
void Foo() {
if (x > 0) {
DoSomething();
}
}
// 类
class Bar {
public:
void Method();
};
❌ 不推荐:
void Foo()
{
if (x > 0)
{
DoSomething();
}
}
常见错误总结
- 使用 Tab 而不是空格
- 行长度超过 80 字符
- 顶层函数/类之间空行不正确
- 运算符、括号、逗号空格使用不一致
- 大括号位置混乱,函数和控制语句不统一
- 多行表达式对齐差,可读性差
5.6. 多行表达式
引言:合理的多行表达式格式可以提高代码可读性,方便理解。
摘要:括号内对齐或换行缩进,保持可读性,不折行过多。
关键词:多行表达式,对齐,缩进,可读性
示例
✅ 推荐:
int result = SomeFunction(a, b,
c, d);
❌ 不推荐:
int result = SomeFunction(a, b, c,
d); // 不对齐,可读性差
常见错误总结
- 使用 Tab 而不是空格
- 行长度超过 80 字符
- 顶层函数/类之间空行不正确
- 运算符、括号、逗号空格使用不一致
- 大括号位置混乱,函数和控制语句不统一
- 多行表达式对齐差,可读性差
6. 规则总结 + 实用建议
引言:总结 Google C++ Style Guide 的核心规则,并提供实用建议。
摘要:总结命名与作用域、头文件、类与函数、注释和格式的规范,并提供统一风格、先写清晰代码、使用静态分析工具、定期 review 代码风格和写好注释等实用建议。
关键词:总结,建议,风格,静态分析,review,注释
6.1. 命名与作用域总结
引言:总结命名与作用域的规范。
摘要:类名使用 驼峰式(CapWords),函数名使用 小写下划线分隔(snake_case),成员变量末尾加 _
,常量全大写,下划线分隔,命名空间尽量限制作用域,头文件不使用 using namespace
,局部变量缩小作用域,循环内定义。
关键词:命名,作用域,驼峰式,下划线,命名空间
常见坑:
- 类名、函数名、成员变量命名不一致
- 全局污染:头文件中使用
using namespace
- 局部变量作用域过大,易引发逻辑错误
6.2. 头文件总结
引言:总结头文件的规范。
摘要:使用 包含保护 或 #pragma once
,包含顺序:对应头文件 → C 标准库 → C++ 标准库 → 第三方库 → 项目头文件,避免循环依赖,使用前向声明。
关键词:头文件,包含保护,包含顺序,循环依赖,前向声明
常见坑:
- 忘记 include guard
- 包含顺序混乱
- 循环依赖未用前向声明
- 混用
.h/.hpp
、.cc/.cpp
6.3. 类与函数总结
引言:总结类与函数的规范。
摘要:类保持单一职责,小而清晰,成员尽量私有,通过公有方法访问,构造函数用初始化列表,析构函数虚化(需要时),函数保持短小,嵌套不深,参数尽量使用 const &
,返回避免悬空引用,拷贝/赋值操作明确(默认、删除或移动语义)。
关键词:类,函数,单一职责,私有成员,构造函数,析构函数,参数,返回值,拷贝,赋值
常见坑:
- 成员变量 public
- 构造函数逻辑复杂
- 函数过长或嵌套太多
- 参数默认值顺序错误
- 返回局部引用或指针
6.4. 注释总结
引言:总结注释的规范。
摘要:每个文件、类、函数应有注释,行内注释简洁明了,TODO 注释署名。
关键词:注释,文件注释,函数注释,行内注释,TODO 注释
常见坑:
- 缺少文件或函数注释
- 行内注释无意义或过长
- TODO 注释无责任人
6.5. 格式总结
引言:总结格式的规范。
摘要:缩进:2/4 空格,禁止 Tab,行长度 ≤ 80 字符,空行:顶层函数/类 2 行,类成员函数 1 行,运算符两边空格,括号/逗号空格规范,大括号:函数/类新行,控制语句同行,多行表达式对齐。
关键词:格式,缩进,行长度,空行,空格,大括号
常见坑:
- 缩进混乱,Tab 与空格混用
- 行过长,影响可读性
- 空行不统一
- 运算符、括号、逗号空格使用不规范
- 大括号位置不一致
- 多行表达式对齐差
6.6. 实用建议
引言:提供实用建议,帮助开发者更好地遵循 Google C++ Style Guide。
摘要:统一整个项目的风格规范,避免个人风格差异,先写清晰、易读代码,再考虑性能优化,频繁使用静态分析工具(clang-tidy, cpplint),定期 review 代码风格,发现偏差及时修正,写好注释,保证团队可维护性。
关键词:风格,静态分析,review,注释,性能优化
实用建议:
- 统一整个项目的风格规范,避免个人风格差异
- 先写清晰、易读代码,再考虑性能优化
- 频繁使用静态分析工具(clang-tidy, cpplint)
- 定期 review 代码风格,发现偏差及时修正
- 写好注释,保证团队可维护性
6.7. 总结
引言:总结 Google C++ Style Guide 的核心内容。
摘要:命名、作用域、头文件、类函数、注释、格式 → 六大核心模块,每个模块有 规则 + 示例 + 常见错误,遵循 Google C++ Style Guide 可以提高代码可读性、可维护性、团队协作效率。
关键词:总结,Google C++ Style Guide,代码可读性,代码可维护性,团队协作效率
总结:
- 命名、作用域、头文件、类函数、注释、格式 → 六大核心模块
- 每个模块有 规则 + 示例 + 常见错误
- 遵循 Google C++ Style Guide 可以提高代码可读性、可维护性、团队协作效率