基于“Google C++ Style Guide”的,由AI总结的一套编码规范(自用)
Google C++ 编码规范总结(学生作业实用版)
适用场景:大学 C++ 编程作业、课程设计、小型个人项目
参考来源:Google C++ Style Guide
目标:写出别人愿意读、自己回头能看懂的 C++ 代码。若老师有指定风格,以老师要求优先。
0. 一页速查表
| 项目 | 规则 | 示例 |
|---|---|---|
| 文件名 | 全小写 + 下划线 | student_record.h |
| 类型名 | 大驼峰 | StudentRecord |
| 变量名 | 小写 + 下划线 | student_name |
| 类成员变量 | 小写 + 下划线 + 结尾下划线 | student_name_ |
| 常量名 | k + 大驼峰 |
kMaxSize |
| 函数名 | 大驼峰 | CalculateGpa() |
| 命名空间 | 小写 + 下划线 | my_project |
| 宏 | 全大写 + 下划线 | MAX_BUFFER_SIZE |
| 枚举值 | k + 大驼峰 |
kColorRed |
| 缩进 | 2 个空格 | 不用 Tab |
| 行宽 | 不超过 80 字符 | 超长要换行 |
| 头文件保护 | #ifndef / #define / #endif |
PROJECT_PATH_FILE_H_ |
| 类型转换 | 用 C++ 风格 | static_cast<int>(x) |
| 空指针 | 用 nullptr |
int* p = nullptr; |
| 只读引用 | 加 const |
const std::string& name |
1. 核心原则
Google C++ Style Guide 的目标不是限制写法,而是管理 C++ 的复杂性。写作业时记住三点:
- 读者优先:代码被阅读的时间远多于被编写的时间,可读性比“写得快”更重要。
- 保持一致:统一命名、缩进、注释风格,让读者能快速抓住结构。
- 规则服务于可读性:不要为了炫技使用复杂特性,简单直接通常更好。
2. 命名规范
2.1 通用原则
- 命名要有描述性,少用缩写。
- 不要吝啬变量名长度,
student_name比sn好。 - 团队/作业中保持一致,不要同一份代码混用多种风格。
2.2 各类命名规则
| 类型 | 规则 | 示例 |
|---|---|---|
| 文件名 | 全小写,下划线分隔 | my_useful_class.cc、http_server_logs.h |
| 类型名 | 大驼峰 | UrlTable、StudentRecord |
| 普通变量 | 小写,下划线分隔 | table_name、num_students |
| 类数据成员 | 小写 + 下划线 + 结尾下划线 | student_name_、grades_ |
| 常量 | k + 大驼峰 |
kDaysInAWeek、kMaxBufferSize |
| 函数名 | 大驼峰 | AddGrade()、CalculateGpa() |
| 命名空间 | 全小写,下划线分隔 | my_project |
| 枚举值 | k + 大驼峰 |
kColorRed、kStatusOk |
| 宏 | 全大写,下划线分隔 | MAX_BUFFER_SIZE |
注意:Google 风格中,常量名通常是
k开头的大驼峰,而不是全大写。全大写一般留给宏。
2.3 示例代码
// 类名用大驼峰
class StudentRecord {
public:
// 普通函数名用大驼峰
void AddGrade(double grade);
double CalculateGpa() const;
// 简单存取器可像变量一样命名
const std::string& student_name() const { return student_name_; }
void set_student_name(const std::string& name) { student_name_ = name; }
private:
// 成员变量小写 + 结尾下划线
std::string student_name_;
std::vector<double> grades_;
};
void StudentRecord::AddGrade(double grade) {
if (grade >= 0.0 && grade <= 4.0) {
grades_.push_back(grade);
}
}
3. 文件与头文件
3.1 头文件保护
所有头文件都应使用 #ifndef / #define / #endif 保护,防止多重包含。命名格式:
#ifndef PROJECT_PATH_FILE_H_
#define PROJECT_PATH_FILE_H_
// ... 声明内容 ...
#endif // PROJECT_PATH_FILE_H_
例如 foo/bar/baz.h:
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
// ...
#endif // FOO_BAR_BAZ_H_
3.2 #include 顺序
按以下顺序包含头文件,每组之间空一行:
// 1. 相关头文件(本 .cc 文件对应的 .h)
#include "foo/server/fooserver.h"
// 2. C 系统头文件
#include <unistd.h>
// 3. C++ 标准库头文件
#include <string>
#include <vector>
// 4. 其他库的头文件
#include "third_party/absl/flags/flag.h"
// 5. 本项目内的头文件
#include "base/basictypes.h"
3.3 前置声明
Google 风格目前建议:尽量避免前置声明,优先 #include 需要的头文件。前置声明虽然能减少编译依赖,但容易引发维护问题和未定义行为。写作业时直接包含头文件更省心。
3.4 内联函数
内联函数只建议用于短小函数,通常不超过 10 行。复杂函数不要强行内联。
4. 作用域与命名空间
4.1 使用命名空间
除少数特殊情况外,代码应放在命名空间中,避免全局命名冲突:
namespace my_project {
namespace foo {
class Bar {
// ...
};
} // namespace foo
} // namespace my_project
注意:命名空间内容通常不额外缩进。
4.2 禁止 using namespace
不要使用 using namespace std; 也不要使用 using namespace foo;。这会把大量名字引入当前作用域,容易冲突。
4.3 匿名命名空间
如果某个函数或变量只在本文件内使用,可放入匿名命名空间:
namespace {
int HelperFunction() {
return 42;
}
} // namespace
5. 类规范
5.1 struct 与 class
仅当只有数据成员、没有方法时使用 struct。其他情况一律使用 class。
struct Point {
double x;
double y;
};
class StudentRecord {
public:
void AddGrade(double grade);
private:
std::string student_name_;
std::vector<double> grades_;
};
5.2 显式构造函数
单参数构造函数应使用 explicit,防止隐式类型转换:
class Foo {
public:
explicit Foo(int x);
};
5.3 访问控制与声明顺序
类中成员声明顺序建议:public: -> protected: -> private:。不要把 protected 和 private 的方法、变量混在一起。
5.4 继承
优先使用组合,而不是继承。如果必须继承,确保基类有合适的析构函数(多态基类用 public virtual 析构,非多态基类用 protected 非虚析构)。
6. 函数规范
6.1 函数应当简短
函数最好短小凝练,一个函数只做一件事。过长函数应拆分为多个小函数。
6.2 参数顺序
参数顺序:输入参数在前,输出参数在后。
void ProcessInput(const std::string& input, std::string* output);
6.3 引用参数
所有按引用传递的参数必须加 const,除非函数需要修改该参数:
void PrintName(const std::string& name); // 好的做法
6.4 返回值
倾向于按值返回。如果返回已有对象,可按引用返回。避免返回指针,除非它可能为空。
7. 常用 C++ 特性建议
7.1 const 与 constexpr
在任何可能的情况下使用 const。编译期常量优先使用 constexpr。
const int kMaxSize = 100;
constexpr double kPi = 3.1415926;
7.2 类型转换
使用 C++ 风格类型转换,不要使用 C 风格转换:
// 好的做法
int y = static_cast<int>(x);
// 不好的做法
int y = (int)x;
7.3 智能指针
优先使用 std::unique_ptr 表示独占所有权。需要共享所有权时使用 std::shared_ptr。避免手动 new / delete。
auto student = std::make_unique<StudentRecord>();
7.4 auto
类型明显时可以使用 auto,但不要滥用。如果类型不明显,写清楚类型更好。
auto it = students.begin(); // 可以
auto count = students.size(); // 可以
7.5 Lambda 表达式
适当使用 lambda。不要使用默认捕获:
// 不好的做法
auto f = [=]() { return x + y; };
// 好的做法
auto f = [x, y]() { return x + y; };
7.6 整数类型
涉及跨平台或明确大小时,使用
#include <cstdint>
int32_t a = 10;
int64_t b = 10000000000LL;
7.7 nullptr
用 nullptr 表示空指针,不要用 NULL 或 0:
int* p = nullptr;
7.8 预处理宏
避免使用宏定义常量或函数,优先使用 const、constexpr、enum class、内联函数。宏只保留给必要的条件编译等场景。
8. 注释规范
8.1 文件注释
每个文件开头应有文件注释。作业中可以写课程、姓名、学号、文件功能:
// 文件名:student_record.cc
// 作者:张三
// 学号:2024xxxxxx
// 功能:实现 StudentRecord 类的相关方法。
8.2 函数注释
函数声明前应说明功能、参数、返回值:
// 计算学生的加权平均分。
// 参数 weighted_scores: 键为课程名,值为 (分数, 权重) 的 pair。
// 返回: 加权平均分,范围 [0.0, 4.0]。
double CalculateWeightedGpa(
const std::map<std::string, std::pair<double, double>>& weighted_scores);
8.3 实现注释
在代码中解释“为什么”,而不是“是什么”。不明显的逻辑要写注释。
8.4 TODO 注释
格式:// TODO(username): 处理输入为空的情况。
9. 格式规范
9.1 基本格式
缩进使用 2 个空格,只用空格不用 Tab。每行不超过 80 个字符。尽量使用 ASCII,非 ASCII 用 UTF-8。函数体左大括号不换行;控制语句左大括号不换行。
9.2 条件语句
if (condition) {
// 2 空格缩进
} else if (other_condition) {
// ...
} else {
// ...
}
9.3 指针和引用
- 和 & 紧跟在类型后面,与变量名之间加空格:
int* ptr;
const std::string& name = GetName();
9.4 布尔表达式
逻辑运算符放在行尾:
if (this_one_thing > this_other_thing &&
a_third_thing == a_fourth_thing &&
yet_another && last_one) {
// ...
}
9.5 循环
for (int i = 0; i < n; ++i) {
// ...
}
for (const auto& student : students) {
// ...
}
10. 作业提交前检查清单
□ 文件名全小写,用下划线分隔。
□ 类型名用大驼峰,变量名用小写加下划线。
□ 类成员变量以 _ 结尾。
□ 常量名用 k 开头的大驼峰。
□ 函数名用大驼峰。
□ 头文件有 #ifndef / #define / #endif 保护。
□ #include 按顺序分组。
□ 没有 using namespace std;。
□ 单参数构造函数用了 explicit。
□ 只读引用参数加了 const。
□ 类型转换使用 static_cast<>() 等 C++ 风格。
□ 空指针使用 nullptr。
□ 缩进 2 个空格,每行不超过 80 字符。
□ 关键函数有注释,复杂逻辑有说明。
□ 编译无警告,尽量使用 -Wall -Wextra。
□ 如果老师有指定风格,优先遵循老师要求。
11. 参考资料
Google C++ Style Guide 英文原版
Google 开源项目风格指南中文版
cpplint 代码检查工具

浙公网安备 33010602011771号