lil_tea C++ Style Guide
说句实话,我一开始也没想到自己会动笔写一份C++风格指南。原因很简单,网上已经有Google C++ Style Guide、LLVM风格、Qt风格这些老牌规范,随便挑一份照着用不就行了?但实际操作下来你会发现,那些官方指南要么太庞杂,要么过于"企业级",对个人项目、小型团队或者正在学C++的朋友来说反而显得笨重。折腾了三四个项目之后,我终于痛下决心,把自己的编码习惯整理成一套轻量、实用、能直接落地的规范,就叫它lil_tea C++ Style Guide。
这份指南不是要推翻Google那套东西,而是把C++开发中最容易踩坑、最影响可读性和维护性的部分挑出来,给出明确且一致的约定。无论你是刚看完C++教程准备写第一个小项目的学生,还是在用VSCode配合CMake折腾个人工具的开发者,或者准备C++面试想理清编码规范的求职者,这份指南都能派上用场。我会结合实际代码示例,把每条规则背后的"为什么"讲清楚——因为只告诉你"该怎么做"而不说"为什么这么做"的规范,是不可能被真正坚持执行的。
1. 为什么我会单独整理一份风格指南
1.1 现成规范和实际开发之间的落差
Google C++ Style Guide确实经典,它对命名、注释、头文件、作用域都有极其详尽的规定。但当你真的在个人项目或者小团队里按它执行时,会遇到一个很现实的问题:它太"重"了。比如Google风格要求成员变量用下划线后缀(count_),这本身没问题,但如果你是在VSCode里做个小工具,突然引入一套需要处处小心的企业级规范,写代码的流畅感会被打断。
另一个常见问题是,很多人对着规范文档看了一遍,转头写代码时就忘了九成。原因在于大多数风格指南都像字典一样只给结论,不给推导过程。我见过不少朋友在C++面试时被问"为什么用const引用传参不用值传递",能背答案但说不清原理。这次整理lil_tea风格指南,我就想改变这种状态——每个约定都配上一句话原理说明,让人记得住、想得通,还能在面试中顺口讲出来。
1.2 这份指南的目标读者和使用边界
我写这份规范时心里有三个目标读者画像。
第一类是自学C++的初学者。刚入门时写的代码往往只有自己能看懂,过了两周自己也看不懂了。风格指南能帮你少走"代码重构"这条弯路。
第二类是维护多个小项目的业余开发者。这类项目不需要跑CI(持续集成),也没有大型代码评审机制,一份轻量规范能起到"虚拟评审官"的作用。
第三类是准备面试的求职者。C++面试经常问内存管理、多线程、STL使用细节,这些内容如果平时编码规范里就严格约束,面试遇到时自然能流利作答。
需要说明的是,这份指南主要面向应用级C++开发(工具类、界面类、中小型服务),不覆盖嵌入式C++或高性能计算库那种极端性能敏感的场景。如果你做的是实时渲染引擎或嵌入式驱动,某些规则需要自行调整。
1.3 我给这份指南预设的三条核心原则
整理过程中我给自己定了三条硬性原则,它们决定了整份指南的走向。
第一,可执行性优先。每条规则都得能在代码评审时明确判定对错,不能出现"尽量避免""尽量使用"这种模糊表述。说"禁止使用"就明确禁止,说"必须"就给出必须的理由。
第二,默认使用现代C++。指南所有示例基于C++17标准,推荐使用的特性也是C++17及以后版本支持的。使用VSCode配置C/C++环境时,我会同步建议开启-std=c++17编译选项。
第三,规则之间不冲突。命名规范、代码结构、内存管理、并发编程这些章节之间必须互相呼应,避免出现"命名要求某风格"和"结构建议另一风格"的矛盾。我踩过这种坑——旧项目半套Google风格半套自己风格,改起来比推倒重写还痛苦。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 命名规范:从三个月后还能看懂自己代码说起
2.1 命名是风格指南里性价比最高的一项
不谈哲学和审美,命名就是编码规范里回报最高的一项投入。试想一下,你三个月前写了一个函数叫void processData(vector<int>& d),现在回来看,你还记得d是什么意思吗?是数据源?是排序后的结果?还是待去重的集合?如果命名规范明确且你严格执行了,即使记不清细节,也能通过名字快速重建代码的意图。
lil_tea风格指南的命名规则直接采用C++社区最常见的共识型方案,不做标新立异。标准如下:
| 对象类型 | 命名方式 | 示例 |
|---|---|---|
| 类型名(class/struct/enum/using别名) | PascalCase | ClassRoomManager |
| 函数名 | PascalCase | SortStudents() |
| 变量名 | 小驼峰 | studentCount |
| 成员变量 | 小驼峰加_后缀 |
studentCount_ |
| 常量名 | k前缀+PascalCase | kMaxRetryTimes |
| 宏名 | 全大写+下划线 | MAX_BUFFER_SIZE |
| 命名空间 | 全小写 | tea_utils |
这套规则和Google风格大体接近,但有一个重要的分岔:函数名我选择统一用PascalCase。为什么?因为C++标准库全是小写下划线风格(std::sort),很多C++入门教程也建议函数用小写。但大型项目里自定义类型和函数经常配合使用,如果函数用下划线风格,调用处会频繁出现priority_queue这种连续小写一长串的情况,视觉辨识度很低。用PascalCase区分"类型名"和"函数名"在视觉上没有差异,但和标准库算法区分更明显,保证自定义函数在代码里能被一眼认出。
当然这不意味着Google风格是错的。如果你在团队里维护老项目,请无条件跟随项目现有风格——新代码风格和旧代码风格不一致,对可维护性的伤害比选哪套风格的伤害更大。
2.2 变量命名的具体约定和常见反例
变量命名是初学者最容易出问题的地方。我的经验是用"量词前缀"而不是"类型前缀"。老式匈牙利命名法讲究iCount、strName这种类型前缀,但现代C++有IDE自动类型推导和智能提示,类型前缀的意义已经不大。
推荐的做法是:
- 布尔量用
is、has、can开头:isReady、hasPermission、canRetry - 容器用
list、set、map结尾:studentList不如students(用单词复数形式更自然) - 指针和智能指针不加特殊前缀,用上下文说明:
unique_ptr<Student> studentPtr中的studentPtr即可,如果觉得不够明确,可以叫currentStudent - 局部临时变量也不要偷懒用
a、b、tmp,用index、leftBorder、tempBuffer这类能回忆功能的名称
我见过最坑的一段代码是:
cpp复制int a = 0;
for (int i = 0; i < n; i++) {
a += arr[i];
}
// a到底是什么?学生人数?总成绩?还是索引?
三行代码就能体现命名问题。改成totalScore、studentCount之后,代码立刻"会说话"了。这就是命名规范的意义——它在帮你降低大脑的认知负担。
2.3 结构体成员命名需不需要遵循特殊规则
结构体和类的成员变量命名,业界有不同流派。Google风格规定普通成员变量加_后缀,静态成员变量加k前缀或_前缀。lil_tea风格对struct和class一视同仁:成员变量统一小驼峰加_后缀,包括public的struct成员。
为什么struct的public字段也要加_?因为C++17引入了结构化绑定,你经常会写:
cpp复制struct Point {
double x;
double y;
};
auto [px, py] = GetPoint();
如果成员变量是x_和y_,解构绑定后直接用px和py,代码可读性依旧很好。而如果混用不同风格的变量名,比如有的成员带_有的不带,后面做初始化列表时极易出错。统一规则,减少决策成本。
2.4 基于命名快速识别变量作用域
我还有一个经验是让"命名风格反映作用域类型"。局部变量用小驼峰,成员变量带_,全局外部变量几乎禁止。这样即便不看上下文,也能知道某个变量是局部的还是成员属性。
这在使用VSCode开发时会特别有感触。鼠标悬停查看类型当然方便,但滚动代码时如果光靠肉眼看变量名就能区分作用域,效率会高很多。
3. 代码排版与结构:让编译器满意,更让人满意
3.1 缩进、大括号和换行规则
排版这件事,我不想花太多篇幅争论"Tab还是空格"这种问题。lil_tea风格的出发点很简单:让代码在Git提交、代码评审工具、各种编辑器下保持高可读性。所以核心约定为:
- 缩进统一用两个空格,不使用Tab
- 大括号采用Allman风格(独占一行)还是K&R风格(括号跟在行尾)?我推荐K&R风格,也就是函数大括号换行,控制语句大括号不换行
cpp复制void ProcessData() { // 函数大括号独占一行
if (isReady) { // 控制语句大括号跟行尾
ProcessCore();
} else {
LogWarning("not ready");
}
}
这里有个容易被忽略的细节:K&R风格在else和while前有一个空格,这是所有风格指南都会强调但实际代码里经常出现的问题。写}else{虽然编译器能过,但阅读跳转语句时极易看花眼。保持} else {的写法,每个词都独立清晰。
换行规则上,原则是每行不超过100个字符。超过就换行,换行后的缩进为上一层缩进加4个空格,括号参数对齐优先:
cpp复制auto result = tea_utils::ComputeAverageScore(studentList,
subjectWeights,
roundingStrategy);
不要小看这个100字符的限制。在VSCode里写C++代码时,分屏对比代码、旁边开着终端跑编译,屏幕横向空间其实很有限。坚持换行不仅方便阅读,还能强迫你拆解过长的表达式,提升代码质量。
3.2 头文件与源文件的结构约定
头文件设计直接影响编译效率。
