本笔记基于 Google C++ Style Guide 整理,聚焦核心规则与常见场景,便于快速查阅。
0. 核心理念
Google 规范的终极宗旨是:可读性 > 一切,一致性 > 个人偏好。代码被阅读的次数远多于被编写的次数——清晰胜于巧妙。
| 原则 | 说明 |
|---|---|
| 可读性优先 | 代码是写给人看的,只是顺便给机器执行 |
| 一致性至上 | 同一项目风格统一比“理论上最优”更重要 |
| 安全与健壮 | 避免隐式类型转换、未定义行为、资源泄漏 |
根据谷歌工程团队统计,遵循统一风格的代码库:新成员上手速度提升65%,代码审查时间减少30%,生产环境 bug 率降低22%。
1. 头文件
1.1 自给自足
——Self-contained
所有头文件必须能够独立编译。用户和重构工具不应为特别场合而包含额外头文件。
// my_class.h
#ifndef MY_PROJECT_MY_CLASS_H_ // ← 必须有头文件保护
#define MY_PROJECT_MY_CLASS_H_
#include <string> // ← 显式包含所有依赖,不依赖间接包含
class MyClass {
public:
explicit MyClass(const std::string& name);
void DoSomething();
private:
std::string name_;
};
#endif1.2 头文件保护
——Include Guard
强制使用
#ifndef格式,禁止#pragma once。
#ifndef PROJECT_DIR_FILE_H_ // 路径相对项目根目录,全大写
#define PROJECT_DIR_FILE_H_
// ...
#endif1.3 前置声明
——Forward Declaration
能前向声明就不
#include,减少编译依赖。
// foo.h
class Bar; // 前置声明,不包含 Bar.h
class Foo {
Bar* bar_; // 仅需指针,不需完整定义
};但不要过度前置声明——头文件仍必须自给自足。
1.4 内联函数
——Inline Functions
仅当函数体极短小(通常 ≤10 行)时使用
inline。内联函数定义必须放在.h文件中。
1.5 #include 顺序
按以下顺序分组,每组之间空一行:
- 本文件对应的头文件(
.cc文件优先包含自己的.h) - C 系统头文件
- C++ 标准库头文件
- 其他库头文件
- 项目内头文件
2. 作用域
2.1 命名空间
必须将代码置于命名空间中(禁用全局命名空间),但禁止
using namespace std;防止污染。
// .h 文件
namespace my_project {
class MyClass { ... };
} // namespace my_project在 .cc 文件中可使用匿名命名空间封装局部辅助函数,使其仅在本编译单元可见。
2.2 局部变量
尽可能在首次使用时声明并初始化,缩小作用域。
2.3 静态和全局变量
禁止使用非 constexpr 的全局变量和静态变量(有静态初始化顺序问题)。
3. 类
3.1 构造函数
避免在构造函数中执行复杂或可能失败的操作。
- 若初始化可能失败,改用工厂函数
- 单参数构造函数必须使用
explicit防止意外隐式转换
class MyClass {
public:
explicit MyClass(int value); // ✅ 防止隐式转换
// MyClass obj = 42; // 编译错误
};3.2 组合 vs 继承
优先选择组合(Composition)。若必须继承,仅使用
public继承。
3.3 结构体 vs 类
struct仅用于纯数据聚合(只有 public 成员,无方法);只要包含方法,必须使用class。
struct Point {
int x;
int y;
}; // ✅ 纯数据,用 struct
class DataProcessor {
public:
void Process();
private:
int data_;
}; // ✅ 有方法,用 class3.4 声明顺序
类内严格按
public:→protected:→private:顺序声明。
4. 现代 C++ 特性
Google 规范在 2025 年版中明确要求使用 C++20 标准,禁止非标准扩展。
| 特性 | 规则 | 说明 |
|---|---|---|
| 智能指针 | 优先 std::unique_ptr,确需共享时用 std::shared_ptr | 严禁 auto_ptr(已弃用) |
| 空指针 | 永远使用 nullptr | 禁止 NULL 或 0 |
| auto 关键字 | 仅限类型冗长或显著提升可读性的场景 | 避免滥用隐藏类型信息 |
| 范围 for 循环 | 优先使用 for (const auto& elem : container) | 减少迭代器错误 |
| 右值引用 | 仅用于移动语义和完美转发 | 不滥用 |
| 异常 | Google 禁用 C++ 异常 | 这是其最显著特色之一,源于性能与控制流可预测性考量 |
| RTTI | 禁用 dynamic_cast 和 typeinfo | |
| 类型转换 | 使用 static_cast / const_cast / reinterpret_cast | 禁止 C 风格 (int)x |
| Lambda | 允许但谨慎使用 | 避免复杂捕获 |
title:Important
Google 已于 2023 年 12 月正式宣布停止维护该规范,并推荐团队根据自身需求采用更现代的实践(如 C++17/20 特性、Clang-Tidy、静态分析等)。但规范的核心思想仍深刻影响着业界。5. 命名约定
Google 规范的最高宗旨之一就是通过命名快速获知名字代表的类型,无需查找声明。
| 元素 | 命名格式 | 示例 |
|---|---|---|
| 文件名 | 全小写 + 下划线 | my_class.cc, http_server.h |
| 类/结构体/枚举 | 帕斯卡拼法(大驼峰) | MyExcitingClass, UrlTable |
| 函数/方法 | 帕斯卡拼法(大驼峰) | DoSomething(), GetValue() |
| 局部变量 | 全小写 + 下划线 | local_variable, index |
| 类成员变量 | 全小写 + 结尾下划线 | health_points_, name_ |
| 常量(const/constexpr) | k + 大驼峰 | kDaysInAWeek, kMaxBuffer |
| 宏定义 | 全大写 + 下划线 | MY_MACRO, LOG_ERROR |
| 命名空间 | 全小写 + 下划线 | my_namespace |
通用命名规则
函数命名、变量命名、文件命名要有描述性,少用缩写。别心疼空间,让代码易于新读者理解更重要。
int price_count_reader; // ✅ 清晰
int num_errors; // ✅ "num" 常见
int n; // ❌ 莫名其妙
int nerr; // ❌ 奇怪缩写
int pc_reader; // ❌ "pc" 含义太多
int cstmr_id; // ❌ 随意删减字母关于私有成员变量以
_结尾而非开头(避免与系统保留标识符冲突),以及全局变量使用g_前缀(极少使用),这些细节应在实际编码中遵循。
6. 格式
| 规则 | 说明 |
|---|---|
| 行长度 | ≤ 80 字符(实际项目可放宽至 100 或 120) |
| 缩进 | 4 空格,禁止使用 Tab |
| 大括号 | Attach 风格:左大括号与语句同一行 |
| 指针/引用 | 星号/& 符号与类型绑定(int* ptr 而非 int *ptr) |
函数声明与定义
void MyFunction(int param1, // 参数过长时换行对齐
const string& param2) {
// ...
}条件与循环
if (condition) { // 左大括号与条件同行
DoSomething();
} else {
DoOtherthing();
}
for (int i = 0; i < 10; ++i) {
Process(i);
}7. 注释
使用
//风格,函数需用 Doxygen 风格注释,说明功能、参数、返回值。
// MyClass.h
class MyClass {
public:
// Computes the average of the given numbers.
// Returns 0 if the list is empty.
double ComputeAverage(const std::vector<double>& numbers);
};TODO 注释
// TODO(username): Fix this edge case when input is empty.8. 争议条款
| 争议项 | 内容 |
|---|---|
| 输出参数:指针 vs 引用 | 早期强制用指针表示输出参数。最新规范已更新,推荐使用引用作为输出参数的首选方式,因为引用天然排除了空指针风险,类型安全更强。当需要可选输出时,考虑 std::optional<T&> |
| 禁止异常 | 这是 Google 规范最具争议的条款,与 C++ Core Guidelines 等现代实践相悖 |
9. 自动化工具
| 工具 | 用途 |
|---|---|
| cpplint | Google 官方提供的代码风格检查工具,可集成到 CI 流程中自动检查是否符合规范 |
| clang-format | 配合 Google 风格配置(BasedOnStyle: Google),自动格式化代码 |
10. 与其他规范的对比
Google 规范与 LLVM 规范是业界两大主流标准,核心差异如下:
| 差异维度 | LLVM | |
|---|---|---|
| 缩进 | 4 空格 | 2 空格 |
| 大括号 | Attach(同行) | Allman(独占一行) |
| using namespace | 禁止 | 允许在模块作用域谨慎使用 |
| 命名 | 禁止下划线前缀 | 允许下划线突出作用域 |
| 异常 | 严格限制 | 更灵活 |