C++理论梳理3——深刻理解头文件的作用

之前写了几篇独立的笔记,现在把他们串在一起捋一遍知识架构。

C++的编译模式和数据共享

C++和C一样支持“独立编译”:代码可放在不同的.cpp里编译成独立的代码块,之后进行各个代码块的链接。如果只改变了单个文件,可以只重新编译该文件,然后和其他文件的编译版本链接。那么不同.cpp的代码块之间如何进行数据交互和共享?通过定义和声明解决:一个变量或函数在一处.cpp中进行定义,其他.cpp需要使用这个数据时对该变量进行声明。

声明和定义

  • 声明使得名字为程序所知,告诉程序本.cpp文件要使用这个变量或函数
  • 定义负责对该变量或函数进行详细设计。
  • 变量的定义只能出现在一个文件中,而使用到它的文件必须对其声明。(不可重复定义,但可以多次声明)
  • 如何实现:extern可声明但不定义,如果对extern进行显式初始化则会抵消extern的作用:变成定义。
int i;		//声明并定义
extern int i;	//声明
extern int i=10; 		//定义

void f();		//声明
void f() {};		//定义

那么我们如何便捷的做到“有且仅一次定义,可多次声明”呢?

.h和.cpp的配合

  1. 可以把【函数原型,#define定义,const定义,结构声明,类声明,模板声明,内联函数】放在一个.h中(如math.h),其定义放在一个.cpp中(如math.cpp)。
  2. A.cpp想使用共享变量或函数时,只需要加一句#include “math.h” 即可
  3. 当.cpp中有#include时,编译过程中编译器可自行在.cpp的文件夹内搜索该.h文件。
  4. 一般情况下,.h文件不可以放变量或函数的定义(可能被多个.cpp包含,而出现重复定义的情况)。但是有特殊情况。
    在这里插入图片描述

特殊情况

.h里也可以放变量和函数的定义:

  1. 头文件可定义const数据,如:const,constexpr。一是因为const默认只在当前文件内有效(一出文件就不可见),若多个文件出现同名const变量,等同于不同文件内的独立变量(对其他文件均不可见),所以便不会导致多重定义。二是因为这样也保证了这些.cpp文件中的这个const对象的值是相同的。
  2. 定义内联函数inline:将代码分成多个函数块优点是明了易读,但可能会增加调用次数影响性能。inline使代码形式上分离(多个函数块),实际上是合并展开的(编译器将他们展开)。inline函数是需要编译器在遇到它的地方根据它的定义把它内联展开,而不是在链接后展开,所以编译器就需要在编译时看到内联函数的完整定义才行。且C++规定,内联函数可以在程序中定义多次,只要内联函数在一个.cpp文件中只出现一次,并且在所有的.cpp文 件中,这个内联函数的定义是一样的,就能通过编译。
  3. 头文件可定义类,且建议头文件名字和类名一致。在程序中创建一个类的对象时,编译器只有在这个类的定义完全可见的情况下,才能知道这个类的对象应该如何布局。值得一提 的是,类的定义中包含着数据成员和函数成员。数据成员是要等到具体的对象被创建时才会被定义(分配空间),但函数成员却是需要在一开始就被定义的,这也就 是我们通常所说的类的实现。一般,我们的做法是,把类的定义放在头文件中,而把函数成员的实现代码放在一个.cpp文件中。这是可以的,也是很好的办法。 不过,还有另一种办法。那就是直接把函数成员的实现代码也写进类定义里面。在C++的类中,如果函数成员在类的定义体中被定义,那么编译器会视这个函数为 内联的。因此,把函数成员的定义写进类定义体,一起放进头文件中,是合法的。

.h关键字

  • #include:出现在.cpp中,作用是把要使用的共享变量或函数包含进本.cpp,相当于复制并插入代码;

  • #define:把一个名字设定为预处理变量;

  • #ifdef:当且仅当预处理变量已定义时为真;

  • #ifndef:当且仅当预处理变量未定义时为真;

  • #endif:一旦检查结果为真,则执行后续操作直到遇到#endif为止。

#ifndef HEADFILE_H
#define HEADFILE_H

/*xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx*/

#endif
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include <assert h>     设定插入点 #include <ctype h>     字符处理 #include <errno h>     定义错误码 #include <float h>     浮点数处理 #include <fstream h>    文件输入/输出 #include <iomanip h>    参数化输入/输出 #include <iostream h>    数据流输入/输出 #include <limits h>     定义各种数据类型最值常量 #include <locale h>     定义本地化函数 #include <math h>      定义数学函数 #include <stdio h>     定义输入/输出函数 #include <stdlib h>     定义杂项函数及内存分配函数 #include <string h>     字符串处理 #include <strstrea h>    基于数组的输入/输出 #include <time h>      定义关于时间的函数 #include <wchar h>     宽字符处理及输入/输出 #include <wctype h>     宽字符分类 int spawnvpe int mode char pathname char argv[] char envp[] spawn函数族在mode模式下运行子程序pathname 并将参数 arg0 arg1 arg2 argv[] envp[] 传递给子程序 出错返回 1 mode为运行模式 mode为 P WAIT 表示在子程序运行完后返回本程序 P NOWAIT 表示在子程序运行时同时运行本程序 不可用 P OVERLAY表示在本程序退出后运行子程序 在spawn函数族中 后缀l v p e添加到spawn后 所指定的函数将具有某种操作能力 有后缀 p时 函数利用DOS的PATH查找子程序文件 l时 函数传递的参数个数固定 v时 函数传递的参数个数不固定 ">#include <assert h>     设定插入点 #include <ctype h>     字符处理 #include <errno h>     定义错误码 #include <float h>     浮点数处理 #include <fstream h>    文件输入/输出 #include <iomanip h& [更多]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值