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. 可以把共享变量或函数的声明放在一个.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

猜你喜欢

转载自blog.csdn.net/IHTY_NUI/article/details/109039636