C++代码整洁之道

article/2025/6/13 20:28:24

整洁的代码在团队中无疑是很受欢迎的,可以高效的被其它成员理解和维护,本文参考《C++代码整洁之道》和《Google C++编码规范》,结合自己的一些想法整理如下:

C++本身作为面向对象语言,首先介绍下面向对象一般涉及到的开发原则。

面向对象开发原则
依赖倒置原则:针对接口编程,依赖于抽象而不依赖于具体,抽象(稳定)不应依赖于实现细节(变化),实现细节应该依赖于抽象,因为稳定态如果依赖于变化态则会变成不稳定态。

开放封闭原则:对扩展开放,对修改关闭,业务需求是不断变化的,当程序需要扩展的时候,不要去修改原来的代码,而要灵活使用抽象和继承,增加程序的扩展性,使易于维护和升级,类、模块、函数等都是可以扩展的,但是不可修改。

单一职责原则:一个类只做一件事,一个类应该仅有一个引起它变化的原因,并且变化的方向隐含着类的责任。

里氏替换原则:子类必须能够替换父类,任何引用基类的地方必须能透明的使用其子类的对象,开放关闭原则的具体实现手段之一。

接口隔离原则:接口最小化且完备,尽量少public来减少对外交互,只把外部需要的方法暴露出来。

最少知道原则:一个实体应该尽可能少的与其他实体发生相互作用。

将变化的点进行封装,做好分界,保持一侧变化,一侧稳定,调用侧永远稳定,被调用侧内部可以变化。

优先使用组合而非继承,继承为白箱操作,而组合为黑箱,继承某种程度上破坏了封装性,而且父类与子类之间耦合度比较高。

针对接口编程,而非针对实现编程,强调接口标准化。

C++开发原则
通过上述面向对象开发原则的理解可以细化到具体C++开发原则。

保持简单和直接原则(KISS, Keep it simple and stupid):保持代码尽可能简单,如果需求需要的话,才在代码中引入灵活的可变点,只添加那些可使整体变得更简单的局部复杂的东西。

不需要原则(YAGNI, You’re not gonna need it):总是在你真正需要的时候再实现他们,而不是在你只是预见到你将来会需要他们而去实现,在真正需要的时候再写代码,那时再重构也来得及。

避免复制原则(DRY, Do not repeat yourself):不要复制,不要重复,这是相当危险的操作,你修改一处代码的时候总能记得去修改另外一处或另外多处你曾经复制的代码吗?

信息隐藏原则:一段代码调用了另外一段代码,调用者不应该知道被调用者代码的实现,否则调用者就有可能修改被调用者的实现来实现某些功能,而这有可能引发其它调用者的bug。

高内聚低耦合原则:类似单一职责原则,明确每个模块的具体责任,尽量少的依赖于其它模块。

最少惊讶原则:函数功能要与函数名字功能一致,难道你要在一个getter()函数去更改成员变量的值吗?

更干净原则(自命名):离开露营地的时候,应让露营地比你来之前还要干净,当发现代码中有需要改进或者风格不好的地方,应该立刻改掉,不要care这段代码的原作者是谁,也不要care这是谁的模块,代码所有权是集体的,每个团队成员在任何时候都应该可以对任何代码进行更改和扩展。

关于面向对象设计原则可以参考一文让你搞懂设计模式

注重单元测试
重要性就不多说了,防患于未然,构建大型系统尤其需要进行单元测试,保证代码质量,可以防患于未然。一般都讲究测试驱动开发,开发一个功能首先要想好怎么测试,先把测试代码写好,再去开发对应的需求。通过单元测试也有利于开发者更好的进行接口的设计,主要说下良好的单元测试的原则。

单元测试的原则
保证单元测试的代码的质量,单元测试的代码也是代码,不应该和产品代码区别对待,而且单元测试的代码再写出bug更影响测试效率。

单元测试的命名, 每个测试单元需要根据具体测试内容进行相应的命名,方便定位分析问题,好的命名如果出现问题时通过测试单元的名字基本就可以定位问题。

保证单元测试的独立性,每个测试单元都是独立的,不依赖于其它测试单元,不要构建测试单元的上下文,上面的测试单元出问题影响到下面的单元测试的设计是很不友好的。

尽量保证一个测试单元使用一个断言,保证测试单元内部的一个相对独立性,上面的断言阻碍了下面的断言测试也是不好的设计。

保证单元测试环境的独立,保证每个测试单元都有独立的环境,不依赖于其它环境,每个测试单元都要是个独立的可运行的实例,每个单元测试结束后记得清理环境。

没必要对第三方库和外部系统做单元测试,只对自己写的代码进行测试。

单元测试尽量不要涉及数据库,数据库的状态是全局的,测试不能保证独立性,而且数据库的访问也是缓慢的,影响单元测试的速度,如果真的需要可以模拟数据库在内容中进行测试,其实通常是在系统集成和系统测试级别时去测试数据库。

不要混淆测试代码和产品代码,产品代码中不应依赖测试代码。

测试必须要快速执行,确保秒级别,大型系统的单元测试也就几分钟而已,单元测试不要访问数据库、磁盘、网络等外设。

找一些测试替身,例如有些数据需要通过网络获取,那可以利用依赖注入做一个网络替身的类模拟这些数据的产生,可以研究研究Google mock。

良好的命名
无论是什么语言,函数和变量的良好命名都是很有必要的,通过函数的名字我们就可以知道这个函数里代码的作用,而不是通过写注释,个人一直倾向于用代码自解释。

文件命名
文件名字要全部小写,中间用_相连,后缀名为.cc和.h

类型命名
类型名称的每个单词首字母均大写, 不包含下划线: MyExcitingClass, MyExcitingEnum.

变量命名
不要将变量的类型在名字中体现,这样以后变量类型改变的话还需要去改动变量名,充分利用IDE的功能,变量 (包括函数参数) 和数据成员名一律小写, 单词之间用下划线连接. 类的成员变量以下划线结尾, 但结构体的就不用, 如: a_local_variable, a_struct_data_member, a_class_data_member_.

常量命名

声明为 constexpr 或 const 的变量, 或在程序运行期间其值始终保持不变的, 命名时以 “k” 开头, 大小写混合

const int kDaysInAWeek = 7;
函数命名
常规函数使用大小写混合, 取值和设值函数则要求与变量名匹配: MyExcitingFunction(), MyExcitingMethod(), my_exciting_member_variable(), set_my_exciting_member_variable().

枚举命名
和常量一致

enum UrlTableErrors {kOK = 0,kErrorOutOfMemory,kErrorMalformedInput,
};

Tip:

除非像swap函数里tmp那种一目了然,否则不要搞无意义的命名,函数名变量名字宁可特别长也要写清楚究竟是什么意思,不要用缩写,一个变量尽量在临近使用前才定义,可读性强也可更好利用cpu cache。

编辑器
团队可以统一使用相同的编辑器,个人目前使用的是VS Code编辑器,同时每个项目使用统一的.clang_format文件,统一规范代码格式,所有的换行符都要用LF格式,不要用CRLF格式,在右下角可以设置。

个人的.clang-format文件如下,是在google风格的基础上做了些修改:

BasedOnStyle: Google
IndentWidth: 4
ColumnLimit: 120
SortIncludes: true
MaxEmptyLinesToKeep: 2

C++编码规范要点小总结

每个头文件都要使用#define避免被重复引用

命名格式 <PROJECT>_<PATH>_<FILE>_H_#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif // FOO_BAR_BAZ_H_

或使用#pragma once,而#define方式更通用

鼓励在 .cc 文件内使用匿名命名空间或 static 声明. 使用具名的命名空间时, 其名称可基于项目名或相对路径. 禁止使用 using 指示, 禁止使用内联命名空间(inline namespace)

一行尽量不要超过120个字符,一个函数尽量不要超过40行,同时一个文件尽量控制在500行内.

所有的引用形参如不做改动一律加const,在任何可能的情况下都要使用 const或constexpr

new内存的地方尽量使用智能指针,c++11 就尽量用std::unique_ptr替代std::auto_ptr

合理使用移动语义,减少内存拷贝,参考左值引用、右值引用、移动语义、完美转发,你知道的不知道的都在这里

禁止使用 RTTI,尽量在编译期间就确定参数类型,不要搞运行时识别typeid这种代码

使用 C++ 的类型转换, 如 static_cast<>(). 不要使用 int y = (int)x 或 int y = int(x) 等转换方式

明确使用前置++还是后置++的具体含义,如不考虑返回值,尽量使用效率高的前置++ (++i)

不要使用uint类型,如果需要使用大整型可以考虑int64,否则类型的隐式类型转换会带来很多麻烦

如无特殊必要不要使用宏,可以考虑使用const或constexpr替代宏,宏的全局作用域很麻烦,如果非要用在马上要使用时才进行 #define, 使用后要立即 #undef

google文档说一定不要用宏来控制条件编译(但是我自己还没有查到不用宏如何控制条件编译,或许就不要搞条件编译)

尽可能用 sizeof(varname) 代替 sizeof(type).使用 sizeof(varname) 是因为当代码中变量类型改变时会自动更新. 您或许会用 sizeof(type) 处理不涉及任何变量的代码,比如处理来自外部或内部的数据格式,这时用变量就不合适了

类型名如果过长的话可以考虑使用auto关键字

注释统一使用 // ,不要通过注释禁用代码,擅用git,不要为易懂的代码写注释

写完代码后记得format,VS Code(windows快捷键) shift + alt + F ,每个项目最好都有统一的.clang_format文件

使用C++的string和stream替代C语言风格的char*,使用std::ostream和std::cout替代printf()、sprintf()等

尽量使用STL标准库的容器而不是C语言风格的数组,数组的越界访问之类当时是不会报错的,反而可能弄脏堆栈信息,导致奇奇怪怪难以排查的bug

可以更多的使用模板元编程,尽量多的使用constexpr等编译器计算,编译器是我们的好搭档,个人认为模板元编程以后会是C++的主流技术

可以考虑更多的使用异常处理方式,而不是C语言风格的errno错误码等,这里可以参考你的c++团队还在禁用异常处理吗?

附:本文不是技术文章,介绍较为主观,可能和很多人想法有所冲突,各位可以结合自己的经历经验酌情参考。

需要学习C++,建议进这个群一起聊,跟前辈一起探讨,也会得到很多帮助。也可以交流学习心得,技术问题,可以获取PDF书籍源码、教程等给大家免费使用 。

f2d082717e3f46168762d845ac802313.png


http://chatgpt.dhexx.cn/article/xdpyg3dG.shtml

相关文章

C++ 代码整洁之道

NOTICE: 这篇文章的框架条目来自《C代码整洁之道&#xff1a;C17可持续软件开发模式实践》&#xff0c;作者: [德] 斯提芬罗特。书籍原名"Clean C: Sustainable Software Development Patterns and Best Practices with C 17"。 NOTICE:未经作者允许禁止转载! 文章目…

SQL中的左连接与右连接,内连接有什么区别

例子&#xff0c;相信你一看就明白&#xff0c;不需要多说 A表(a1,b1,c1) B表(a2,b2) 左连接&#xff1a; select A.,B. from A left outer join B on(A.a1B.a2) 结果是: 右连接&#xff1a; select A.,B. from A right outer join B on(A.a1B.a2) 结果是: 内连接&#xff1a…

sql左连接、右连接结果总结

班级team 表 班级和教师连接表team_teacher – 左连接: – 对于左连接&#xff0c;查询结果中&#xff0c;left左边表格的记录会全部包含 – 再到left右边表格查&#xff0c;如果匹配结果是0或1&#xff0c;对结果总数没影响 – 如果匹配条数大于1&#xff0c;那么结果就增加…

内连接,左连接和右连接作用

在数据库查询中&#xff0c;经常会遇到多表连接来查询数据&#xff0c;下面来说一下他们的连接方法和作用 内连接&#xff1a;内连接是很常用的一个连接方法&#xff0c;用来查询两个表或者多个表之间相同的数据&#xff0c;例如&#xff1a; 查询的是他们之间相同的数据 内…

SQL中的连接(左、右、内连接)

目录 左连接&#xff08;LEFT JOIN或LEFT OUTER JOIN&#xff09;&#xff1a; 右连接&#xff08;RIGHT JOIN或RIGHT OUTER JOIN&#xff09;&#xff1a; 内连接&#xff08;INNER JOIN也叫等值连接&#xff09;&#xff1a; 全连接&#xff08;FULL JOIN&#xff09;&…

SQL内连接,左连接,右连接区别及联系

目录 数据库建表及其内容 内连接&#xff08;默认连接&#xff09; 左连接 右连接 总结&#xff1a; 数据库建表及其内容 stu表 班级表&#xff08;class&#xff09; 内连接&#xff08;默认连接&#xff09; SELECT stu.stuname , classname FROM class INNER JOIN stu…

SQL中左连接和右连接的理解误区

SQL中左连接和右连接的理解误区&#xff1a; 1.左右外连接中&#xff0c;怎么区分哪个表当左表&#xff0c;哪个表当右表&#xff1f; 2.什么时候用左连接&#xff0c;什么时候用右连接&#xff1f; 首先&#xff0c;重新捋一遍二者概念&#xff1a; 左连接的语法&#xff…

SQL语句什么是左连接、右连接、内连接?

1、左连接 以左表为基础&#xff0c;根据ON后给出的两表的条件将两表连接起来。结果会将左表所有的查询信息列出&#xff0c;而右表只列出ON后条件与左表满足的部分。 左表&#xff08;table1&#xff09;全部保留&#xff0c;右表&#xff08;table2&#xff09;关联不上用n…

sql的左连接,右连接,内连接

环境&#xff1a; SQL工具&#xff08;如Navicat&#xff0c;SQLyog&#xff09; MySQL驱动 全局总结&#xff1a; 左连接:关注左边&#xff0c;右边没有就为空。右连接:关注右边&#xff0c;左边没有就为空。内连接:返回交集 必备&#xff1a; 两张或多张表格 一&#x…

Linux系统之iostat命令的基本使用

Linux系统之iostat命令的基本使用 一、iostat命令介绍二、iostat命令帮助1.1 iostat的帮助信息1.2 iostat的选项解释 三、iostat命令的基本使用3.1 查看iostat工具版本3.2 直接使用iostat命令3.3 间隔5秒查看3次信息3.4 只查看磁盘状态3.5 以k或M为单位显示信息 四、查看磁盘I/…

Linux实时监控iostat命令详解

概述&#xff1a; iostat 主要用于输出CPU和磁盘I/O相关的统计信息。 格式&#xff1a; iostat [选项] [<时间间隔>] [<次数>] 如图 参数&#xff1a; -c 显示CPU使用情况 -d 显示磁盘使用情况 -N 显示磁盘阵列(LVM) 信息 -n 显示NFS 使用情况 -k 以 KB 为单位显…

服务器 iostat命令详解

iostat是I/O statistics&#xff08;输入/输出统计&#xff09;的缩写&#xff0c;iostat工具将对系统的磁盘操作活动进行监视。它的特点是汇报磁盘活动统计情况&#xff0c;同时也会汇报出CPU使用情况。iostat也有一个弱点&#xff0c;就是它不能对某个进程进行深入分析&#…

Linux中iostat命令参数详解

iostat主要用于监控系统设备的IO负载情况&#xff0c;iostat首次运行时显示自系统启动开始的各项统计信息&#xff0c;之后运行iostat将显示自上次运行该命令以后的统计信息。用户可以根据需求指定相应的次数和时间。 一、使用iostat 1命令&#xff1a; 各参数含义 Device:部…

转:linux iostat命令详解

转过来学习学习。 Linux系统中的 iostat是I/O statistics&#xff08;输入/输出统计&#xff09;的缩写&#xff0c;iostat工具将对系统的磁盘操作活动进行监视。它的特点是汇报磁盘活动统计情况&#xff0c;同时也会汇报出CPU使用情况。同vmstat一样&#xff0c;iostat也有一个…

iostat linux,centos安装iostat命令的方法详解

在centos系统中,可以使用yum命令安装iostat。 开始,想当然地运行命令: 复制代码 代码示例: #yum install iostat 出现如下图所示的提示: 经搜索后,知道使用yum安装iostat,需要安装的其实是sysstat。 例如: 复制代码 代码示例: #yum install sysstat 出现如下图所示的安装…

iostat 命令详解(二)

iostat 命令详解(二) iostat常用命令如下: 1,iostat 2,iostat -xk 1 1 3,iostat -dk 1 1 查看吞吐量 总结:

Linux中iostat含义,linux下iostat命令详解

iostat语法 用法&#xff1a;iostat [ 选项 ] [ [ ]] 常用选项说明&#xff1a; -c&#xff1a;只显示系统CPU统计信息&#xff0c;即单独输出avg-cpu结果&#xff0c;不包括device结果 -d&#xff1a;单独输出Device结果&#xff0c;不包括cpu结果 -k/-m&#xff1a;输出结果以…

iostat命令详解——linux性能分析

之前总结uptime和free命令&#xff0c;今天继续来总结一下iostat。给自己留个笔记&#xff0c;同时也希望对大家有用。 版本信息&#xff1a; sysstat version 9.0.4 (C) Sebastien Godard (sysstat <at> orange.fr) 基本使用&#xff1a; iostat [ -c ] [ …

Linux 性能分析之iostat命令详解

Linux 性能分析之iostat命令详解 iostat命令是IO性能分析的常用工具&#xff0c;其是input/output statistics的缩写。本文将着重于下面几个方面介绍iostat命令&#xff1a; iostat的安装iostat命令行选项说明iostat输出内容分析如何确定磁盘IO的瓶颈iostat实际案例 命令的安…

Linux命令---iostat命令详解

简介 iostat主要用于监控系统设备的IO负载情况&#xff0c;iostat首次运行时显示自系统启动开始的各项统计信息&#xff0c;之后运行iostat将显示自上次运行该命令以后的统计信息。用户可以通过指定统计的次数和时间来获得所需的统计信息。 语法 iostat [ -c ] [ -d ] [ -h ] […