提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
TODO:写完再整理
本文先对代码规范的一些经验做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章
提示:以下是本篇文章正文内容
有编程规范有利于代码的快速阅读、更改
.
.
常量参数优先用宏定义,出现数字是很难被理解的
一些需要进行调节的参数必须定义为#define的形式,不然不直观,甚至很难进行更改!
通常不应该使用宏,如果一定要使用,其命名单词全部大写,由下划线连接
#define PI_ROUNDED 3.0
命名时以“k”开头,大小写混合
const int kDaysInAWeek = 7;
变量(包括函数参数)和数据成员名一律小写,单词之间用下划线连接。
local_variable,struct_data_member
命名的首要原则是名副其实,每个命名都要力求有意义且简洁\
动词小写、名词大写(尽量使用名词和动名词的方法来命名)
函数的命名一般使用动名词。变量的的命名一般使用名词
函数是动名词、变量和类是动词的命名方式
.
【后下划线代表全局】
类名和对象名应该是名词或者名词短语,且开头大写,多名词组合的独立名词首字母也要大写,如Customer、WikiPage
即以大写字母开始,每个单词首字母均大写,不包含下划线,如:
class MyClass {}
struct MyStruct {}
函数名(方法名)应该是动词或者动词短语,且开头动词小写,动词与名词组合的名词大写。如deletePage、savePage、getPage
函数名的首个单词小写,其他单词首字母大写,单词之间不使用下划线等,一般情况下,取函数首个单词为动词
addTwoNumber()
getSum()
文件名要全部小写,以下划线”_”连接不同单词。
不要使用已经存在与/usr/include 下的文件名。
把函数设计成实现一个最小功能的单元就好,只做一件小事情,多个小事情组合成为一个大事情。
一个函数只做一件事情
(1)一个函数代码量尽量在30行左右为佳。函数越长阅读起来越费劲,迁移和组合难度越大!功能越死板改动一下功能都更难。如果函数超过30 行,可以思索一下能不能在不影响程序结构的前提下对其进行分割。
(2)各个函数是嵌套关系的,因为阅读代码一般是自顶向下阅读的,因此每个函数都要归为一类,一般分为:底层的实现函数、中间层的逻辑组合函数、顶层的业务功能函数三类
工厂函数的接口
const 变量
const 变量,数据成员,函数和参数为编译时类型检测增加了一层保障; 便于尽早发现错误。
如果函数不会修改你传入的引用或指针类型参数,该参数应声明为const。
函数的输入输出
函数的参数顺序为:输入参数在先,后跟输出参数。(若输入参数是不可以改变的用const关键字修饰,输出参数可以使用引用“&”和指针“*”)
bool类型或者枚举类型的输出用函数类型进行return,数据类型的输出用&XXX的取地址符号进行传递,一般输入的变量在函数中不能被改变的(如定位的pose)必须用const进行修饰。
初始化列表的方法
若传入对象比较复杂,可以传入参数列表嘛,本质还是用一个更大的数据接口包含一系列小的变量
若函数太长,或者函数有较多重复的函数调用,这时候就要考虑函数的封装了使得函数更加能够理解读懂,使得代码不要那么臃肿,同时保证代码短小精简
串联逻辑用if/else,并联逻辑用switch/case
只有当函数只有 10 行甚至更少时才将其定义为内联函数。通常内联函数不包含循环、switch 语句,且不是递归函数。
(1)一般函数的输出一定要有接口,函数不依赖任何全局变量(不要在外面定义一个全局变量,在函数内使用全局变量达到参数传递的效果)
(2)若是输入或者输出的参数较多,且参数都属于一类的数据,可以定义一个类,并用这个类实例化一个对象,把对象作为参数传进去函数。函数就可以访问对象里面的所有成员。
(3)一般的函数尽量不要定义成void类型的,至少定义成一个bool类型的,或者是枚举errorcode类型的。没有返回值的函数挂了也检测不出来。
(4)尽量编写一元函数和二元函数,传入传出参数过多调用函数设置的时候就复杂,同时函数头也比较长不美观(传入对象而非一个参数变量能解决这个问题)

(6)区分输入参数和输出参数的直观方法:输出参数一般用const甚至没有修饰,输出参数用引用&和指针*进行标志
若一行代码过长,或者函数传入的参数过多,为了格式对齐要用分隔符“/”进行隔断
可以理解的前提下,尽可能少的注释
有多余的注释测试完成,功能可用后要及时整理删除更新
(1)在调试代码的时候可以写下注释,再通过测试后应该删除注释,并把原来的注释翻译简化留下基本的提醒就好。
(2)注释本质是一个提醒,边测试边修改,验证错误的注释必须马上删除
(3)注释是写程序的中间产物,程序员是不会维护注释的,注释停留的时间越长信息描述越不准确(程序在变化,注释也要跟着变化)
使用一看就懂的变量和函数命名方式,一写出来的代码就知道这个函数变量的意思
尽量不要去写注释的方向去做
代码在测试阶段还有价值就先别删掉,测试完毕没有价值的代码或者是就方案的代码就可以删除掉了,甚至定义的函数但没有被调用的函数一样可以被删除掉。
代码整洁的排版需要一套简单的格式规则
(0)代码的空格和缩进要有规范
(1)注意在一行代码中代码不宜过长–使用分隔符
(2)注意作用域的缩进格式–使用标准的TEB键
(3)注意代码行和代码行之间不能有空行,函数与函数之间空一行就行
(4)注意判断与赋值符号两边都要留有空格,空格字符有强调的作用
(5)函数的形参一般在括号出不留空格,在逗号后面加一个空格,强调变量的数量
(6)变量定义在符合作用域的前提下,尽量与调用位置靠近,不必集中的定义在一个地方(全局变量定义在使用它的函数前面)
(7)函数在头文件声明的位置
相关概念的函数声明应该放在一起,甚至定义成一个类。函数的共性越强,当的距离应该更近一些
(6)类和枚举的一些变量垂直应该对齐,缩进适当

(9)在while、for、if这些语句后的大括号要留下一个{,if/else相互嵌套时,if else不能分开,不然条件嵌套关系不明显
(10)如果while、for这些语句的循环是空的也要用大括号{},尽量不要只写一个分号,迷惑性极强
对象和数据结构的格式
(1)类内public的成员是别人可以用的
(2)类内privide是自己用的
(3)类内函数和类内变量要分开写,宁可多写几个public和privide的关键字
(4)类的内容应该尽可能小,类是同一性质成员的最小单元。类与类之间可以继承和友元使用,代码越长越难理解
(5)抽象出来同一层次的类,同一层次的类使用工厂设计模式!提供标准的参考模板

在try/catch中尽量不要有太多的代码,最好再进行一次函数封装,使得try/catch的结构更加清晰,示例如下:

这个需要函数是errorcode的数据类型的,一般返回错误代码是用于调试输出的(看log),使用异常事件是用于系统底层做出对应动作的(看warning和error的系统信息)。程度不一样。
一般有一个Errorcode.h的文件对应
Errorcode的方式

(1)当一个源文件过大的时候就应该考虑把一个源文件进行拆分。用一个更好一级的源文件include拆分的文件,整合调用
(2)一个源文件尽量仅仅使用一种编程语言,避免混编(不同编程语言的规范不太一样的)
所有头文件都应该使用#define 防止头文件被重复包含

1、所有继承必须是 public 的。
2、必要的话,析构函数声明为 virtual。如果你的类有虚函数,则析构函数也应该为虚函数
3、数据成员都必须是私有的,将所有数据成员声明为 private,除非是 static const 类型成员。
4、不要过度使用 protected 关键字。
(1)先有一个大方向架构目标,再从具体的每个小模块进行重构,重构一次不完美就重构第二次,修改格式绝对不可能一次完成的
系统框架应该是最简单易懂的设计,若系统架构都是难以理解的逻辑,在该系统框架下的代码肯定是更加复杂的逻辑【大道至简】
当想要加入一点代码变得更加难,需要考虑到复杂的逻辑的时候就要重新梳理逻辑和工程架构了
代码架构设计的学习(把方法论整理出来)
一开始就不注重代码架构设计和规范,到最后面只会越走越难。即使是推倒重来也只能快跑一段时间跑不远的(无轨迹不成方圆)
架构的理解不是一朝一夕的事情,是需要不断理解、不断实践、不断维护的!同时架构是满足业务的需要,同时已于理解的!
架构是一种代码设计模式(模块)和流程规划的形式,代码有规有矩,避免脏乱差,难以二次开发!
代码组织(大方面)–物皆有其位,而后尽其位【架构师】
(每段代码都应该出现在你设计的该有的位置上,如果该段代码不在这里,就应该重构代码,使得代码找到他该在的位置)
分task或者节点的原因
1、每个task的运行频率不一样
2、对模块之间进行解耦,开发逻辑更清晰
移植使用第三方代码需要根据我们的工程情况为第三方代码在封装一些函数接口,以保证代码的边界性
看懂别人的代码,最好自己手撕一次!
移植的心得
除非是算法小黑盒,不然移植还是要靠自己理解了去移植,因为业务和环境不一样
写代码和写论文是一样的,第一步先把内容写出来,第二步再封装整理使得格式和结构达到符合规范!
打磨代码的方法:分解函数、修改名称、消除重复、重新设置架构、抽象成类同时保证测试通过。
都是需要时间一关一关的过的!
不同代码的测试方法不一样,只要可以通过测试的最后一关就说明生产代码是符合标准的!
(1)方法一:使用文字和指令告诉测试工程师测试方法,让可是工程师在不同场景做测试
(2)方法二:把指令封装到bash文件中,一键启动
仅当只有数据成员时使用 struct,其它一概使用 class。
同一作用范围和层次的变量或者函数要抽象成结构体和类
变量尽量不要定义成全局变量,如果不得已要定义成全局变量,也要把一类的全局变量封装到一个类中,实例化一个类从而定义一个全局变量,最好还要给该类修饰一个作用域namespace
尽可能使用智能指针,避免内存泄露。倾向于使用 std::unique_ptr 明确所有权传递。如果要使
用共享所有权,建议使用 std::shared_ptr。不要使用 std::auto_ptr,使用 std::unique_ptr 代替它。
auto 关键字可以自动匹配变量和函数的数据类型,用 auto 绕过烦琐的类型名,只要可读性好就继续用,别用在局部变量之外的地方。
使用 C++ 的类型转换,如 static_cast<>()。不要使用 int y = (int)x
或 int y = int(x)等转换方式。
整数用 0,实数用 0.0,指针用 nullptr(C++ 11),字符 (串) 用 ‘\0’。
(1)标准一:经过测试后上传的代码i顶是最精炼的,别人值在乎代码的过程,不会在乎代码的结果
(2)标准二:符合团队的编程格式要求!
代码不可冗长、不可重复、具有表达力
https://zh-google-styleguide.readthedocs.io/en/latest/google-cpp-styleguide/