连载文章,长期更新,欢迎关注:
写在前面
第1章-ROS入门必备知识
第2章-C++编程范式
2.1 C++工程组织结构
2.2 C++代码编译方法
2.3 C++编程风格指南
...
更多精彩内容,持续更新中......
大家如有任何技术问题,欢迎加入QQ技术群(117698356),进群一起交流讨论
要熟练地运用编程技术开发项目,离不开好的编程素养。依照一套好的编程风格的规范,不仅能在编程过程中规避很多低级错误,还能够显著提升团队的开发效率。当然,不同的项目、不同的团队都有适合其实际情况的规范标准。一般推荐参考行业内的一些权威规范标准,比如2009版谷歌C++编程风格指南就非常不错。下面将带领大家解读2009版谷歌C++编程风格指南,让初学者理解编程规范的重要性并养成遵守规范的好习惯。
2.3.1 头文件
头文件用于声明变量、函数、类以及定义一些简短的内联函数,关于头文件的规范见表2-1所示。
表2-1 头文件规范
| 规范 | 说明 |
| 条件编译 | #ifnded FOO_H_ #define FOO_H_ ... #endif 头文件内容用条件编译限定,防止一个源文件多次包含该头文件 |
| 内联函数 | 只有当函数在10行或更少时,才将其定义为内联函数。函数体较小时,内联函数能提高运行效率,比如存取函数之类的。复杂的内联函数的定义,应放在后缀名为-inl.h 的头文件中 |
| 函数参数顺序 | 输入参数在前,输出参数在后。输入参数一般传值或常数引用,输出参数或输入/输出参数为非常数指针 |
| 包含文件顺序 | 包含文件排列顺序为C库头文件、C++库头文件、第三方库头文件、项目内头文件 |
2.3.2 作用域
避免变量名称混淆和方便阅读,需要在C++代码中合理地使用作用域。关于作用域的规范见表2-2所示。
表2-2 作用域规范
| 规范 | 说明 |
| 命名空间 | 命名空间将全局作用域细分为不同名称的作用域,能防止全局作用域的命名冲突。最好不要使用 using指示符,以保证名称前面的命名空间都显式地出现 |
| 嵌套类 | 可以在类中定义另一个类,即嵌套类。只在被嵌套类中使用时,将其放置于被嵌套类作用域中,能避免污染其他作用域下的同名类 |
| 非成员函数、静态成员函数 | 使用命名空间中的非成员函数或静态成员函数,尽量不要使用全局函数 |
| 局部变量 | 将函数变量尽可能置于最小作用域内,并在声明变量时将该变量初始化。属于对象的变量,尽量放在循环作用域外进行声明,避免每次循环都调用对象的构造函数 |
| 全局变量 | 禁止使用类的实例对象作为全局变量,当然多线程代码中非常数全局变量也是被禁止的,禁止使用函数返回值初始化全局变量 |
2.3.3 类
类的众多特性赋予C++强大的功能,这里就挑一些重点的特性出来分析。关于类的规范见表2-3所示。
表2-3 类规范
| 规范 | 说明 |
| 构造函数 | 构造函数中只进行没有实际意义的初始化,如果需要进行有意义的初始化,请使用Init()函数并增加一个成员用于标记是否已经初始化成功。如果没有定义构造函数,编译器会自动生成默认构造函数。对单参数的构造函数,请用关键词explicit限定。程序中需要拷贝一个对象时,使用拷贝构造函数,应适当定义拷贝构造函数和赋值操作符 |
| 结构体 | 只有数据成员时可以使用结构体,其他情况一律使用类 |
| 继承 | 使用组合通常比使用继承更适宜,如果使用继承的话,只使用公共继承。当重定义派生的虚函数时,在派生类中明确声明其为virtual,帮助开发人员快速确定继承来的函数属性。多重继承允许子类拥有多个基类,要将作为纯接口的基类和具有实现的基类区别开来 |
| 数据存取 | 将数据成员私有化,并提供相关存取函数,比如为成员变量foo_提供取值函数get_foo()和赋值函数set_foo()。存取函数的定义一般内联在头文件中 |
| 声明顺序 | 按公有、保护和私有顺序,没有的块直接忽略。块内按下面声明顺序: 1) typedefs 和 enums |
| 成员函数 | 函数尽量短小以便于阅读和修改。超过40行的函数,不影响程序结构可以考虑拆分 |
2.3.4 命名约定
遵守一套命名约定的规范,能显著提升代码的可读性。关于命名约定的规范见表2-4所示。
表2-4 命名约定规范
| 规范 | 说明 | |
| 通用约定 | 函数名、变量名、文件名等应该具备描述性,不要过度缩写 | |
| 文件名 | 全部小写,可以包含下划线。 | my_useful_class.h my_useful_class.cpp my_useful_class-inl.h |
| 命名空间 | 全部小写,名字基于项目名和目录结构。 | google_test_project |
| 类型名 | 大写字母开头,无下划线,类、结构体、类型定义、枚举 | class ImageProcess{...} |
| 变量名 | 普通变量 类成员变量 全局变量 | string image_name string image_name_ string g_image_name |
| 函数名 | 普通函数 存取函数 | LoadImage() get_foo()和set_foo() |
| 常量名 | 加前缀k | const int kDaysInWeek=7 |
| 枚举 | 枚举名属于类型,因此大小写混合;枚举值全部大写,单词间用下划线分隔 | enum WorkStates{ OK=0,IN_ERROR=1,OUT_ERROR=2} |
| 宏 | 全部大写,单词间用下划线分隔 | #define PI_PARAM 3.14 |
【1】 张虎,机器人SLAM导航核心技术与实战[M]. 机械工业出版社,2022.



