C++ 全栈知识体系C++ 全栈知识体系
✿导航
  • 基础
  • 函数
  • 知识点
  • IO框架
  • 新版本特性
  • 数据库原理
  • SQL语言
  • SQL - MySQL
  • NoSQL - Redis
  • NoSQL - ElasticSearch
  • 算法基础
  • 常见算法
  • 领域算法
  • 分布式算法
  • 数据结构与算法
  • 计算机网络
  • 操作系统
  • 计算机组成
  • 开发
  • 测试
  • 架构基础
  • 分布式系统
  • 微服务
  • 中间件
  • 概念
  • 理论
  • 架构设计原则
  • 设计模式
  • 协议
  • 技术选型
  • 编码规范
  • 流水线构建 - CI/CD
  • 知识点 - Linux
  • 网站 - Nginx
  • 容器化 - Docker
  • 容器编排 - Kubernetes
  • 服务网格 - Service Mesh Istio
  • 常用快捷键 - Shortcut
  • 工具使用 - Tools
  • 开源项目
  • 学习项目
  • 个人项目
  • 项目开发
  • 项目Idea
  • 并发
  • 部署
  • 分布式
  • 知识
  • 问题
  • 编程语言与技术
  • 系统与架构
  • 软件开发实践
  • 数据处理与应用设计
  • 个人
  • 产品
  • 团队
  • 知识体系
  • Vue
关于
✿导航
  • 基础
  • 函数
  • 知识点
  • IO框架
  • 新版本特性
  • 数据库原理
  • SQL语言
  • SQL - MySQL
  • NoSQL - Redis
  • NoSQL - ElasticSearch
  • 算法基础
  • 常见算法
  • 领域算法
  • 分布式算法
  • 数据结构与算法
  • 计算机网络
  • 操作系统
  • 计算机组成
  • 开发
  • 测试
  • 架构基础
  • 分布式系统
  • 微服务
  • 中间件
  • 概念
  • 理论
  • 架构设计原则
  • 设计模式
  • 协议
  • 技术选型
  • 编码规范
  • 流水线构建 - CI/CD
  • 知识点 - Linux
  • 网站 - Nginx
  • 容器化 - Docker
  • 容器编排 - Kubernetes
  • 服务网格 - Service Mesh Istio
  • 常用快捷键 - Shortcut
  • 工具使用 - Tools
  • 开源项目
  • 学习项目
  • 个人项目
  • 项目开发
  • 项目Idea
  • 并发
  • 部署
  • 分布式
  • 知识
  • 问题
  • 编程语言与技术
  • 系统与架构
  • 软件开发实践
  • 数据处理与应用设计
  • 个人
  • 产品
  • 团队
  • 知识体系
  • Vue
关于
  • 概念

    • 概念 - 概述
    • 概念 - 计算机专有名词
    • 概念 - 正向代理和反向代理
    • 概念 - 云网络
    • 概念 - rest api
    • 概念 - 脑裂
  • 理论

    • 事务理论 - ACID
    • 分布式理论 - CAP
    • 分布式理论 - BASE
  • 架构设计原则

    • 架构设计原则 - 合适、简单、演化
    • 架构设计原则 - 高内聚、低耦合
    • 架构设计原则 - 正交四原则
    • 架构设计原则 - SOLID详解
    • 架构设计原则 - 分层架构MVC
    • 架构设计原则 - DDD领域驱动设计:贫血模型和充血模型
    • 架构设计原则 - DDD领域驱动设计
  • 设计模式

    • 创建型模式 - Create model

      • 创建型模式 - 单例模式(Singleton)
      • 创建型模式 - 工厂模式(Factory)
      • 创建型模式 - 抽象工厂(Abstract Factory)
      • 创建型模式 - 生成器(Builder)
      • 创建型模式 - 原型模式(Prototype)
    • 结构型模式 - Structural model

      • 结构型模式 - 外观(Facade)
      • 结构型模式 - 适配器(Adapter)
      • 结构型模式 - 桥接(Bridge)
      • 结构型模式 - 组合(Composite)
      • 结构型模式 - 装饰(Decorator)
      • 结构型模式 - 享元(Flyweight)
      • 结构型模式 - 代理(Proxy)
    • 行为型模式 - Behavioral model

      • 行为型模式 - 责任链(Chain Of Responsibility)
      • 行为型模式 - 策略(Strategy)
      • 行为型模式 - 模板模式(Template)
      • 行为型模式 - 命令模式(Command)
      • 行为型模式 - 观察者(Observer)
      • 行为型模式 - 访问者(Visitor)
      • 行为型模式 - 状态(State)
      • 行为型模式 - 解释器(Interpreter)
      • 行为型模式 - 迭代器(Iterator)
      • 行为型模式 - 中介者(Mediator)
      • 行为型模式 - 备忘录(Memento)
  • 协议

    • 协议 - Http
    • 协议 - SNMP
    • 协议 - NETCONF
    • 协议 - TLS和SSL
    • 协议 - Http-wiki
    • 协议 - TCP/IP
    • 协议 - Https常见的认证模式
  • 技术选型

    • 技术选型 - 常用的技术框架
    • 技术选型 - 如何写一个自己的项目
    • 技术选型 - 基于drogon实现用户中心后端
  • 编码规范

    • 编码规范 - Google C++ Style Guide
    • 编码规范 - 编程风格
    • 编码规范 - 头文件包含规范
    • 编码规范 - 常用编码命名规则
    • 编码规范 - 编码命名规范

编码规范 - 头文件包含规范

  • Self-contained 头文件自包含
  • 头文件中尽量减少对其他头文件的依赖
    • 多余的头文件包含
    • 可以在source文件包含的,不要包含着头文件中
    • 使用前置声明(forward declarations)
  • 避免错误依赖和反向依赖
  • 尽可能将代码拆分成相对独立的,粒度小的单元,放到不同的文件中
  • 包含头文件顺序

C/C++头文件包含规范

Self-contained 头文件自包含

  • 所有头文件要能够自给自足,即头文件需要包含本身依赖的其他头文件。
  • 换言之,用户和重构工具不需要为特别场合而包含额外的头文件。

头文件中尽量减少对其他头文件的依赖

  • 头文件包含另一个头文件的同时会引入一项新的依赖(dependency),这个依赖也会随着该头文件的被包含而扩散出去,从而导致依赖扩散。

  • 只要头文件被修改,代码就要重新编译,如果你的头文件包含了其它头文件,这些头文件的任何改动都将导致那些包含了你的头文件的代码重新编译。

多余的头文件包含

  • 头文件包含必须遵循最少必要原则,尽量少包含。
  • 能包含小的头文件,不包含大的头文件。
  • 及时清理不需要的头文件包含,不能只增不删。

可以在source文件包含的,不要包含着头文件中

例如,Test.h头文件以及对应Test.cpp -->


Test.h只要包含改头文件所依赖的其他头文件,不能将Test.cpp -->
```所需要用到的头文件全都放在Test.h中。

### 头文件仅声明,不作实现

如果头文件里包含函数实现,在其他多个源文件中使用include方式包含时,会提示多重定义(multiple definition)

### 头文件是只包含必要的声明

* 不是所有函数实现都需要在头文件中声明,只声明需要发布的函数接口。

* 私有函数不在头文件中声明,从而减少头文件的依赖。例如,某些工具类方法可以声明和实现在.cpp -->
```函数的类外。

### define 保护

* 所有头文件都应该使用 #define 来防止头文件被多重包含, 命名格式例如: 

```cpp
#ifndef Data_MySQL_MySQLException_INCLUDED
#define Data_MySQL_MySQLException_INCLUDED

使用前置声明(forward declarations)

  • 「前置声明」(forward declaration)是类、函数和模板的纯粹声明,没伴随着其定义.

看法一:

  • 尽可能地避免使用前置声明。使用 #include 包含需要的头文件即可。
  • 前置声明隐藏了依赖关系,头文件改动时,用户的代码会跳过必要的重新编译过程。

看法二:

  • 通过前置声明的方式,减少头文件中依赖的其他头文件。将头文件的包含动作延迟到源文件中去实现。

  • 使用场景:头文件只用到对应内容的指针或引用不涉及具体内容。或用到一个结构体声明,但不想包一个很大的头文件将依赖扩散。(struct Foo;在源文件中#include <Foo.h>)

可以参考:C++前置声明

避免错误依赖和反向依赖

  • 包含每个头文件时,需要分析是不是合适的依赖,避免包含错误的头文件,导致其依赖的其他头文件项变多。
//log.h

#include<logType.h>
#include<logTime.h>

//不应该包含项
#include<message.h>
#include<httpType.h>

尽可能将代码拆分成相对独立的,粒度小的单元,放到不同的文件中

  • 不能使得一个类代码很臃肿,包含特别多的功能,不方便维护。

  • 通过拆分成小的,独立的模块更利于维护。

包含头文件顺序

头文件Test.h和源文件Test.cpp -->


1. Test.h (如果自己定义的头文件有错,编译时会提前暴露自身的错误而不是其他库的。)
2. 本项目内的.h文件
3. 其它库的.h文件
4. C系统文件
5. C++系统文件

没有唯一的标准,都是适合自己的习惯,google C++ 头文件顺序:

1. 主体功能文件(这一条规则保证维护这些文件的人们首先看到构建中止的消息而不是维护其他包的人们。)
2. C系统文件
3. C++系统文件
4. 其它库的.h文件
5. 本项目内的.h文件

## 包含头文件时,使用源码的目录树结构,不使用相对路径

使用源码的目录树结构,而不是相对路径:

* 为保证唯一性, 头文件的命名应该基于所在项目源代码树的全路径

* #include <drogon/orm/Result.h>  √
* #include <../../Result.h>       ×

## 头文件中不允许使用using namespace XXX·措施

* 头文件使用 `using namespace XXX` 会破坏 namespace 的封装性
* 因为头文件会被包含在其他的头文件和cpp文件中。导致C++编译器将头文件字符串直接拷贝,强制其他的头文件也使用 `using namespace XXX`,从而引起编译错误,或者使用错误的类型,造成麻烦。

```cpp
//正例
namespace HttpProxy{
    using Poco::ByteOrder;
    using Poco::UInt16;
}

// 反例

namespace HttpProxy{
    using namespace Poco;
}

保证措施

  • 代码扫描工具识别多余包含
  • Code Review发现头文件包含是否规范
Last Updated:
Contributors: klc407073648
Prev
编码规范 - 编程风格
Next
编码规范 - 常用编码命名规则