#include 如何在C++中工作

How does #include work in C++?

本文关键字:工作 C++ #include      更新时间:2023-10-16

如果一个库包含在类头中,然后这个头文件包含在另一个类中,我是否必须再次包含该库?

例如:

#ifndef A_H
#define A_H
#include<someLibrary.h>
class A{
  ...
}
#endif

然后另一个类包含 A.h 标头

#include<A.h>   //include class A
class B{
   ...
}

我是否必须在B类中包含"someLibrary.h"?

不,#include 是可传递的。

但是,如果您的第二个文件本身使用 someLibrary 中的符号,则重新包含标头是一种很好的样式。这样你就不会"希望和祈祷"你永远不会删除中间包含。如果每个源文件都#include它直接需要的所有内容,您的代码库将更加健壮。标头保护可防止这成为浪费策略。

预处理器 #include 指令完全按照名称的含义执行,它实际上包含指令位置的文件。

简单的例子:假设我们必须文件,首先是一个名为a.h的头文件

// Our class
class A
{
    // Stuff for the class
};
// End of the class

然后源文件a.cpp

// Include header file
#include "a.h"
// Header file included
int main()
{
    // Code
}

预处理器生成一个文件,如下所示

// Include header file
// Our class
class A
{
    // Stuff for the class
};
// End of the class
// Header file included
int main()
{
    // Code
}

此包含是递归的,因此如果头文件包含另一个头文件,则还将包含该其他头文件。

预处理器生成的源文件称为翻译单元,是编译器实际看到的内容。


以上是对现代预处理器工作方式的简化,虽然可以单独运行以创建预处理的源文件,但更常见的是预处理器是编译器的一部分,以简化解析过程。


您还应该注意,您使用的术语不正确。库可以(并且通常确实)有一个或多个头文件,这些文件在编译源代码时使用。然后,库通常(但并非总是)包含一个特殊的库文件,该文件与编译器创建的目标文件链接

没有链接器库的库称为仅标头库。

你不包含类或库,你只包含标头,这是一个文本操作(有点像预处理器完成的复制和粘贴)。

阅读更多关于 C/C++ 预处理器和 GNU cpp 的信息。

您可以要求编译器向您显示源文件的预处理形式foo.cc,例如带有g++ -Wall -C -E foo.cc(它将溢出到标准输出预处理形式)

对于一个小项目(例如小于 200KLOC),所有翻译单元只包含一个公共头文件是明智的(我相信有很多小头文件是坏习惯,所以我通常为每个头文件放置多个类定义)。顺便说一句,这种(单头文件)方法对预编译头很友好。有些人更喜欢在单个标题中有几个自己的 #include -d 子标题。

请注意,大多数C++标准标头(如<map><vector>...)都会带来大量文本,因此您不希望使用微小的编译单元(在我的Linux系统上,#include <vector>拖动了一万多行,因此之后只有几十行源代码对于编译器来说是低效的)

另请注意,类定义通常C++内联成员函数(并且您实际上希望在同一头文件中提供该内联函数的主体)。所以C++标题代码往往很大...

(有些人喜欢在许多子标题中打破单个头文件,这些子标题总是一起包含)