1.头文件规则

1.1 #define防止多重包含

所有头文件都应该使用#define防止头文件被多重包含,这个多重包含指的是一个cpp编译过程中不被多次包含,如果有多个cpp都调用,那这个文件还是会被包含多次,所有头文件中不要做定义。

命名格式如果是普通的业务逻辑类的代码比如x_msg_task.h的文件就直接定义 X_MSG_TASK_H,如果是做类库或者公用的库,把项目名称加在前面。

例如:

  1. #ifndef X_MSG_TASK_H
  2. #define X_MSG_TASK_H
  3. // 声明代码
  4. #endif

1.2 减少文件依赖

使用前置声明(forward declarations)尽量减少.h 文件中 #include 的数量。

当一个头文件被包含的同时也引入了一项新的依赖(dependency),只要该头文件被修改, 代码就要重新编译。如果你的头文件包含了其他头文件,这些头文件的任何改变也将导致那些包含了你的头文件的代码重新编译。因此,我们宁可尽量少包含头文件,尤其是那些包含 在其他头文件中的。

比如Qt中,如果用到 QPushButton 类的指针,在头文件中可以不 #include 类文件,而是直接用 class QPushButton; 的声明,但如果类中定义的是实体对象,那就必须要引入头文件。

在.h 中尽量不引用头文件,在.cpp 中引用。

例如:

  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3. #include <QLabel>
  4. #include <QMainWindow>
  5. QT_BEGIN_NAMESPACE
  6. namespace Ui {
  7. class MainWindow;
  8. }
  9. class QPushButton;
  10. // class QLabel; 使用这个第26行报错,因为变量lable是实体对象
  11. QT_END_NAMESPACE
  12. class MainWindow : public QMainWindow {
  13. Q_OBJECT
  14. public:
  15. MainWindow(QWidget* parent = nullptr);
  16. ~MainWindow();
  17. private:
  18. Ui::MainWindow* ui;
  19. QPushButton* pushButton;
  20. QLabel label;
  21. };
  22. #endif // MAINWINDOW_H

1.3 头文件中不导入命名空间

头文件中不调用 using 导入命名空间,调用是直接写命名空间比如 std::string str;

命名空间导入在 .cpp 中做,因为你没法确认你的 .h 会被什么样的文件调用,会不会参数命名冲突。

2.格式规则

2.1 空格还是制表位(Spaces vs Tabs)

只使用空格,每次缩进4个空格。(其实可以通过编译器控制)

使用空格,在不同程序打开格式不会乱。主要是统一,不能spaces tabs混用

2.2 括号格式

左右括号都单独起一行

  1. if (true)
  2. {
  3. //
  4. }

3.命名约定

3.1 通用命名规则

函数命名、变量命名、文件命名应具有描述性,不要过度缩写,类型和变量应该是名词,函数名可以用“命令性”动词

3.2 文件命名

文件名要全部小写,可以包含下划线( _ )。如 my_useful.cpp

3.3 Class类型命名

类型命名每个单词以大写字母开头,不包含下划线:MyExcitingClassMyExcitingEnum

所有类型命名 — 类、结构体、类型定义(typedef)、枚举类型 — 使用相同约定

3.4 变量命名

变量名一律小写,单词间以下划线相连,类的成员变量以下划线结尾,如 my_exciting_local_variablemy_exciting_member_variable_

3.5 函数命名

普通函数
函数名以大写字母开头,每个单词首字母大写,没有下划线:AddTableEntry()

成员存取函数

  1. class MyClass { // google风格
  2. public:
  3. ...
  4. int num_entries() const {
  5. return num_entries_;
  6. }
  7. void set_num_entries(int num_entries) {
  8. num_entries_ = num_entries;
  9. }
  10. private:
  11. int num_entries_;
  12. };

3.6 宏、枚举命名

使用全部大写+下划线

枚举名称属于类型,因此大小写混合:UrlTableErrors

  1. enum UrlTableErrors
  2. {
  3. oK = 0,
  4. ERROR_OUT_OF_MEMORY,
  5. ERROR_MALFORMED_INPUT,
  6. };

4 类规则

4.1 构造函数的职责

构造函数中只进行那些没有实际意义的初始化就是非业务逻辑的初始化,尽量在 Init() 方法集中初始化业务逻辑数据。

4.2 结构体和类

仅当只有数据时使用 struct,其它一概使用 class。类和结构体的成员变量使用不同的命名规则。

4.3.继承

优先使用组合,如果必须使用继承的话,只使用 public 继承。

4.4 多重继承

尽量不用,如果必须要用,多重继承中只有一个基类是有实现的,其他的都只能是接口类,不然内部对象空间分配容易产生问题。

4.5 接口

接口是指满足特定条件的类,这些类以 I 开头(非必需)。

只有纯虚函数(”=0”)和静态函数

4.6 声明次序

在类中使用声明次序如下:public:protected:private:每一块中,声明次序一般如下:

  • 构造函数
  • 析构函数
  • 成员函数,含静态成员函数
  • 数据成员,含静态数据成员

5 Doxygen 注释规则

5.1 文件注释

文件注释通常放在整个文件开头。

5.1.1 项目注释

  1. ///////////////////////////////////////////////////////////////////////////
  2. /// @mainpage 项目注释
  3. /// @author 作者
  4. /// @version 版本
  5. /// @date 2021 年03 月07 日
  6. ///////////////////////////////////////////////////////////////////////////

5.1.2 文件注释

  1. ///////////////////////////////////////////////////////////////////////////
  2. /// @file 文件名
  3. /// @brief 简介
  4. /// @details 细节
  5. ///////////////////////////////////////////////////////////////////////////

5.2.类定义注释

  1. ///////////////////////////////////////////////////////////////////////////
  2. /// @brief 类的简单概述
  3. /// @details 类的详细概述
  4. ///////////////////////////////////////////////////////////////////////////

5.3.常量/变量的注释

  1. /// 代码前注释
  2. 常量/变量
  3. 常量/变量 ///< 代码后注释,一般是变量数量较多,并且名字短

5.4.函数注释

  1. ///////////////////////////////////////////////////////////////////////////
  2. /// @brief 函数简介
  3. ///
  4. /// @param 形参 参数说明
  5. /// @param 形参 参数说明
  6. /// @return 返回说明
  7. ///////////////////////////////////////////////////////////////////////////

5.5.Doxygen设置使用

需要下载

设定项目名称和项目语言

设定编码方式(INPUT_ENCODEING)VS 的项目一般设置为 GBK