头文件的规范使用

我们知道C++是一门比较复杂的语言,养成良好的代码规范对我们在以后的工作中维护项目,阅读别人的项目等都有很大的作用,因此学习了google代码规范。
几乎每个cpp文件都会包含一个.h头文件。正确使用头文件可以使代码在可读性,文件大小,性能方面大大改观,下面的一些规则可以使我们避免头文件的一些陷阱。

1.Self-contained头文件
就是说要保证你的头文件是自给自足的,一个自足的头文件是一个不依赖于它包含在那里的上下文来正确工作的文件。如果你在使用它之前确定#include或定义/声明了所有内容,那么你有自己足够的标题。
可能大家对于这个没什么概念。我举个栗子:
----- MyClass.h -----

class MyClass
{
MyClass(std::string s);
};

---- MyClass.cpp -----
#include “MyClass.h”
#include
MyClass::MyClass(std::string s)
{…}
我们在.h头文件中,用到了string这个源文件,但是在cpp文件中,我们先声明头文件,最后会出现string没有包含这个错误,因为头文件不是自给自足的。只有#include 放在#include "MyClass.h"才行,所以为了避免这种错误,我们需要使头文件满足自给自足这个条件。所以我们的头文件写完必须独立运行编译一下看看是否成功,为此,我们需要在头文件中包含其他所有的文件,在这个例子中,myclass中应该包含string这个文件。

2、#define保护
所有头文件都应该使用 #define 来防止头文件被多重包含,命名格式为:
H .例如, 项目 foo 中的头文件 foo/
src/bar/baz.h 可按如下方式保护:
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_

#endif // FOO_BAR_BAZ_H
为保证唯一性, 头文件的命名应该基于所在项目源代码树的全路径.
到这里大家可能还是不理解防止头文件被多重包含是如何实现的。大家需要了解一下预处理器。预处理就是在编译之前对源文件进行简单的加工。我们最熟悉的是#include和#define。

最常见的预处理有:文件包含,条件编译、布局控制和宏替换4种。
文件包含:#include 是一种最为常见的预处理,主要是做为文件的引用组合源程序正文。
条件编译:#if,#ifndef,#ifdef,#endif,#undef等也是比较常见的预处理,主要是进行编译时进行有选择的挑选,注释掉一些指定的代码,以达到版本控制、防止对文件重复包含的功能。
其中#undef是取消宏定义,和#define是一对。
#if,#endif和我们的if,else用法很像,是条件编译,满足条件才会执行,他和if的区别就是,if后面可以有变量,而#if必须跟整形常量表达式。
#ifdef的作用是判断某个宏是否定义,如果该宏已经定义则执行后面的代码,一般使用格式如下
#ifdef 宏名
程序段1
#else
程序段2
#endif
它的意思是,如果该宏已被定义过,则对程序段1进行编译,否则对程序段2进行编译(这个和上面的#if一样最后都需要#endif),上述格式也可以不用#else,这一点上和if else相同
#ifndef恰好和#ifdef相反,未被定义则执行。
到这里,大家应该明白为什么#ifndef 可以达到不重复包含头文件的作用。

布局控制:#pragma,这也是我们应用预处理的一个重要方面,主要功能是为编译程序提供非常规的控制流信息。比如通过#pragma once也可以实现头文件重复包含问题,但是由于兼容性,我们还是推荐使用#ifndef。
宏替换:#define,这是最常见的用法,它可以定义符号常量、函数功能、重新命名、字符串的拼接等各种功能。这个大家都很熟悉。

3.前置声明
原则:尽量避免前置声明,使用#include包含需要的头文件即可。
前置声明是类,函数,模板的纯粹声明,没有定义。
前置声明的优点:
• 前置声明能够节省编译时间,多余的 #include 会迫使编译器展开更多的文件,处理更多的输入。
• 前置声明能够节省不必要的重新编译的时间。#include 使代码因为头文件中无关的改动而被重新编译多次。

缺点:
• 前置声明隐藏了依赖关系,头文件改动时,用户的代码会跳过必要的重新编译过程。
• 前置声明可能会被库的后续更改所破坏。前置声明函数或模板有时会妨碍头文件开发者变动其 API. 例如扩大形参类型,加个自带默认参数的模板形参等等。
• 前置声明来自命名空间 std:: 的 symbol 时,其行为未定义。
• 很难判断什么时候该用前置声明,什么时候该用 #include 。极端情况下,用前置声明代替 includes 甚至都会暗暗地改变代码的含义。

4.内联函数
只有在函数代码少于10行才使用内联函数。
如果代码量很多的话,内联函数会使代码量增多。而且复杂度比调用函数开销还大。因为小巧的代码执行更快。
并且当函数中包含循环和switch时,不应该使用内联函数。
对于析构函数,因为有隐含成员和基类析构函数的调用,代码比表面看起来长,因此要谨慎对待。
并且,对于递归函数,就算你内联,编译器也不允许。因为递归层数在编译期间是未知的,不向循环展开这么简单。
5.include 的路径和顺序
使用标准的头文件包含顺序可增强可读性, 避免隐藏依赖: 相关头文件, C 库, C++ 库, 其他库的.h, 本项目内的 .h。
至于原因我们就不仔细说了,感觉并不是很重要。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值