为什么 C++ 需要一个单独的头文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1305947/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:29:54  来源:igfitidea点击:

Why does C++ need a separate header file?

c++language-design

提问by Marius

I've never really understood why C++ needs a separate header file with the same functions as in the .cpp file. It makes creating classes and refactoring them very difficult, and it adds unnecessary files to the project. And then there is the problem with having to include header files, but having to explicitly check if it has already been included.

我从来没有真正理解为什么 C++ 需要一个单独的头文件,其功能与 .cpp 文件中的功能相同。它使创建类和重构它们变得非常困难,并且会向项目添加不必要的文件。然后是必须包含头文件的问题,但必须明确检查它是否已经被包含。

C++ was ratified in 1998, so why is it designed this way? What advantages does having a separate header file have?

C++ 是在 1998 年批准的,那么为什么它是这样设计的呢?单独的头文件有什么好处?



Follow up question:

跟进问题:

How does the compiler find the .cpp file with the code in it, when all I include is the .h file? Does it assume that the .cpp file has the same name as the .h file, or does it actually look through all the files in the directory tree?

当我只包含 .h 文件时,编译器如何找到包含代码的 .cpp 文件?它是否假定 .cpp 文件与 .h 文件具有相同的名称,或者它实际上是否查看了目录树中的所有文件?

采纳答案by Steve Jessop

You seem to be asking about separating definitions from declarations, although there are other uses for header files.

您似乎在询问将定义与声明分开,尽管头文件还有其他用途。

The answer is that C++ doesn't "need" this. If you mark everything inline (which is automatic anyway for member functions defined in a class definition), then there is no need for the separation. You can just define everything in the header files.

答案是 C++ 并不“需要”这个。如果您将所有内容都标记为内联(这对于在类定义中定义的成员函数来说是自动的),则不需要分离。您可以在头文件中定义所有内容。

The reasons you might wantto separate are:

您可能想要分开的原因是:

  1. To improve build times.
  2. To link against code without having the source for the definitions.
  3. To avoid marking everything "inline".
  1. 改善构建时间。
  2. 在没有定义源的情况下链接代码。
  3. 避免将所有内容标记为“内联”。

If your more general question is, "why isn't C++ identical to Java?", then I have to ask, "why are you writing C++ instead of Java?" ;-p

如果您更普遍的问题是“为什么 C++ 与 Java 不相同?”,那么我必须问,“您为什么要编写 C++ 而不是 Java?” ;-p

More seriously, though, the reason is that the C++ compiler can't just reach into another translation unit and figure out how to use its symbols, in the way that javac can and does. The header file is needed to declare to the compiler what it can expect to be available at link time.

然而,更严重的是,原因是 C++ 编译器不能像 javac 那样,直接进入另一个翻译单元并弄清楚如何使用它的符号。需要头文件向编译器声明它在链接时可以使用的内容。

So #includeis a straight textual substitution. If you define everything in header files, the preprocessor ends up creating an enormous copy and paste of every source file in your project, and feeding that into the compiler. The fact that the C++ standard was ratified in 1998 has nothing to do with this, it's the fact that the compilation environment for C++ is based so closely on that of C.

所以,#include是直文本替换。如果您在头文件中定义所有内容,预处理器最终会创建项目中每个源文件的大量复制和粘贴,并将其提供给编译器。C++ 标准在 1998 年获得批准的事实与此无关,而是 C++ 的编译环境与 C 的编译环境如此密切相关。

Converting my comments to answer your follow-up question:

转换我的评论以回答您的后续问题:

How does the compiler find the .cpp file with the code in it

编译器如何找到包含代码的 .cpp 文件

It doesn't, at least not at the time it compiles the code that used the header file. The functions you're linking against don't even need to have been written yet, never mind the compiler knowing what .cppfile they'll be in. Everything the calling code needs to know at compile time is expressed in the function declaration. At link time you will provide a list of .ofiles, or static or dynamic libraries, and the header in effect is a promise that the definitions of the functions will be in there somewhere.

它不会,至少在它编译使用头文件的代码时不会。您链接的函数甚至不需要已经编写,更不用说编译器知道.cpp它们将在哪个文件中。调用代码在编译时需要知道的一切都在函数声明中表达。在链接时,您将提供一个.o文件列表,或者静态或动态库,并且标题实际上是对函数定义将在其中某处的承诺。

回答by Donald Byrd

C++ does it that way because C did it that way, so the real question is why did C do it that way? Wikipediaspeaks a little to this.

C++ 那样做是因为 C 那样做,所以真正的问题是为什么 C 那样做?维基百科对此略作说明。

Newer compiled languages (such as Java, C#) do not use forward declarations; identifiers are recognized automatically from source files and read directly from dynamic library symbols. This means header files are not needed.

较新的编译语言(如 Java、C#)不使用前向声明;标识符从源文件中自动识别并直接从动态库符号中读取。这意味着不需要头文件。

回答by jalf

Some people consider header files an advantage:

有些人认为头文件是一个优势:

  • It is claimed that it enables/enforces/allows separation of interface and implementation -- but usually, this is not the case. Header files are full of implementation details (for example member variables of a class have to be specified in the header, even though they're not part of the public interface), and functions can, and often are, defined inline inthe class declaration in the header, again destroying this separation.
  • It is sometimes said to improve compile-time because each translation unit can be processed independently. And yet C++ is probably the slowest language in existence when it comes to compile-times. A part of the reason is the many many repeated inclusions of the same header. A large number of headers are included by multiple translation units, requiring them to be parsed multiple times.
  • 据称它启用/强制/允许分离接口和实现——但通常情况并非如此。头文件充满了实现细节(例如,必须在头文件中指定类的成员变量,即使它们不是公共接口的一部分),并且函数可以并且经常类声明中内联定义在标题中,再次破坏了这种分离。
  • 有时据说可以改善编译时间,因为每个翻译单元都可以独立处理。然而,就编译时间而言,C++ 可能是现存最慢的语言。部分原因是同一标题的许多重复包含。多个翻译单元包含大量标头,需要对其进行多次解析。

Ultimately, the header system is an artifact from the 70's when C was designed. Back then, computers had very little memory, and keeping the entire module in memory just wasn't an option. A compiler had to start reading the file at the top, and then proceed linearly through the source code. The header mechanism enables this. The compiler doesn't have to consider other translation units, it just has to read the code from top to bottom.

最终,标题系统是 70 年代设计 C 时的产物。当时,计算机的内存很少,将整个模块保存在内存中并不是一种选择。编译器必须从顶部开始读取文件,然后线性地遍历源代码。标头机制实现了这一点。编译器不必考虑其他翻译单元,它只需要从上到下读取代码。

And C++ retained this system for backwards compatibility.

为了向后兼容,C++ 保留了这个系统。

Today, it makes no sense. It is inefficient, error-prone and overcomplicated. There are far better ways to separate interface and implementation, if thatwas the goal.

今天,这没有意义。它效率低下,容易出错且过于复杂。如果是目标,那么有更好的方法来分离接口和实现。

However, one of the proposals for C++0x was to add a proper module system, allowing code to be compiled similar to .NET or Java, into larger modules, all in one go and without headers. This proposal didn't make the cut in C++0x, but I believe it's still in the "we'd love to do this later" category. Perhaps in a TR2 or similar.

然而,C++0x 的建议之一是添加一个适当的模块系统,允许将代码编译为类似于 .NET 或 Java 的更大的模块,所有这些都是一次性的,没有头文件。这个提议在 C++0x 中没有被削减,但我相信它仍然属于“我们希望稍后再做”的类别。也许在 TR2 或类似的。

回答by Michael Stum

To my (limited - I'm not a C developer normally) understanding, this is rooted in C. Remember that C does not know what classes or namespaces are, it's just one long program. Also, functions have to be declared before you use them.

根据我的(有限的 - 我通常不是 C 开发人员)的理解,这植根于 C。请记住,C 不知道什么是类或命名空间,它只是一个很长的程序。此外,函数必须在使用之前声明。

For example, the following should give a compiler error:

例如,以下应该给出编译器错误:

void SomeFunction() {
    SomeOtherFunction();
}

void SomeOtherFunction() {
    printf("What?");
}

The error should be that "SomeOtherFunction is not declared" because you call it before it's declaration. One way of fixing this is by moving SomeOtherFunction above SomeFunction. Another approach is to declare the functions signature first:

错误应该是“SomeOtherFunction 未声明”,因为您在声明之前调用了它。解决此问题的一种方法是将 SomeOtherFunction 移到 SomeFunction 之上。另一种方法是先声明函数签名:

void SomeOtherFunction();

void SomeFunction() {
    SomeOtherFunction();
}

void SomeOtherFunction() {
    printf("What?");
}

This lets the compiler know: Look somewhere in the code, there is a function called SomeOtherFunction that returns void and does not take any parameters. So if you encouter code that tries to call SomeOtherFunction, do not panic and instead go looking for it.

这让编译器知道:在代码中的某个地方,有一个名为 SomeOtherFunction 的函数,它返回 void 并且不带任何参数。因此,如果您遇到试图调用 SomeOtherFunction 的代码,请不要惊慌,而是去寻找它。

Now, imagine you have SomeFunction and SomeOtherFunction in two different .c files. You then have to #include "SomeOther.c" in Some.c. Now, add some "private" functions to SomeOther.c. As C does not know private functions, that function would be available in Some.c as well.

现在,假设您在两个不同的 .c 文件中有 SomeFunction 和 SomeOtherFunction。然后你必须在 Some.c 中 #include "SomeOther.c"。现在,向 SomeOther.c 添加一些“私有”函数。由于 C 不知道私有函数,因此 Some.c 中也可以使用该函数。

This is where .h Files come in: They specify all the functions (and variables) that you want to 'Export' from a .c file that can be accessed in other .c files. That way, you gain something like a Public/Private scope. Also, you can give this .h file to other people without having to share your source code - .h files work against compiled .lib files as well.

这就是 .h 文件的用武之地:它们指定您想要从 .c 文件中“导出”的所有函数(和变量),这些 .c 文件可以在其他 .c 文件中访问。这样,您就可以获得类似于公共/私有范围的东西。此外,您可以将此 .h 文件提供给其他人,而无需共享您的源代码 - .h 文件也适用于已编译的 .lib 文件。

So the main reason is really for convenience, for source code protection and to have a bit of decoupling between the parts of your application.

所以主要原因真的是为了方便、源代码保护以及在应用程序的各个部分之间进行一些解耦。

That was C though. C++ introduced Classes and private/public modifiers, so while you could still ask if they are needed, C++ AFAIK still requires declaration of functions before using them. Also, many C++ Developers are or were C devleopers as well and took over their concepts and habits to C++ - why change what isn't broken?

不过那是C。C++ 引入了类和私有/公共修饰符,因此虽然您仍然可以询问是否需要它们,但 C++ AFAIK 仍然需要在使用它们之前声明函数。此外,许多 C++ 开发人员也是或曾经是 C 开发人员,并将他们的概念和习惯转移到 C++ 中 - 为什么要改变没有破坏的东西?

回答by erelender

First advantage: If you don't have header files, you would have to include source files in other source files. This would cause the including files to be compiled again when the included file changes.

第一个优势:如果您没有头文件,则必须在其他源文件中包含源文件。这将导致在包含文件更改时再次编译包含文件。

Second advantage: It allows sharing the interfaces without sharing the code between different units (different developers, teams, companies etc..)

第二个优势:它允许共享接口,而无需在不同单位(不同的开发人员、团队、公司等)之间共享代码。

回答by VoidPointer

The need for header files results from the limitations that the compiler has for knowing about the type information for functions and or variables in other modules. The compiled program or library does not include the type information required by the compiler to bind to any objects defined in other compilation units.

需要头文件是由于编译器在了解其他模块中的函数和/或变量的类型信息方面存在局限性。编译后的程序或库不包括编译器绑定到其他编译单元中定义的任何对象所需的类型信息。

In order to compensate for this limitation, C and C++ allow for declarations and these declarations can be included into modules that use them with the help of the preprocessor's #include directive.

为了弥补这一限制,C 和 C++ 允许声明,并且可以在预处理器的 #include 指令的帮助下将这些声明包含到使用它们的模块中。

Languages like Java or C# on the other hand include the information necessary for binding in the compiler's output (class-file or assembly). Hence, there is no longer a need for maintaining standalone declarations to be included by clients of a module.

另一方面,Java 或 C# 等语言在编译器的输出(类文件或程序集)中包含绑定所需的信息。因此,不再需要维护模块的客户端包含的独立声明。

The reason for the binding information not being included in the compiler output is simple: it is not needed at runtime (any type checking occurs at compile time). It would just waste space. Remember that C/C++ come from a time where the size of an executable or library did matter quite a bit.

编译器输出中未包含绑定信息的原因很简单:运行时不需要它(任何类型检查都发生在编译时)。只会浪费空间。请记住,C/C++ 来自一个可执行文件或库的大小确实很重要的时代。

回答by Daniel Earwicker

C++ was designed to add modern programming language features to the C infrastructure, without unnecessarily changing anything about C that wasn't specifically about the language itself.

C++ 旨在将现代编程语言功能添加到 C 基础架构中,而不会不必要地更改任何与 C 语言本身无关的内容。

Yes, at this point (10 years after the first C++ standard and 20 years after it began seriously growing in usage) it is easy to ask why doesn't it have a proper module system. Obviously any new language being designed today would not work like C++. But that isn't the point of C++.

是的,在这一点上(第一个 C++ 标准出现 10 年后,它的使用量开始严重增长 20 年后)很容易问为什么它没有合适的模块系统。显然,今天设计的任何新语言都不会像 C++ 那样工作。但这不是 C++ 的重点。

The point of C++ is to be evolutionary, a smooth continuation of existing practise, only adding new capabilities without (too often) breaking things that work adequately for its user community.

C++ 的重点是进化,是现有实践的平稳延续,只添加新功能而不(经常)破坏对其用户社区充分工作的东西。

This means that it makes some things harder (especially for people starting a new project), and some things easier (especially for those maintaining existing code) than other languages would do.

这意味着与其他语言相比,它使某些事情变得更难(尤其是对于开始新项目的人),而某些事情(尤其是对于维护现有代码的人而言)更容易。

So rather than expecting C++ to turn into C# (which would be pointless as we already have C#), why not just pick the right tool for the job? Myself, I endeavour to write significant chunks of new functionality in a modern language (I happen to use C#), and I have a large amount of existing C++ that I am keeping in C++ because there would be no real value in re-writing it all. They integrate very nicely anyway, so it's largely painless.

因此,与其期望 C++ 变成 C#(因为我们已经有了 C#,这将毫无意义),为什么不为这项工作选择合适的工具呢?我自己,我努力用现代语言编写大量新功能(我碰巧使用 C#),并且我有大量现有的 C++ 保留在 C++ 中,因为重写它没有真正的价值全部。无论如何,它们集成得非常好,因此在很大程度上是无痛的。

回答by Mark Krenitsky

Well, C++ was ratified in 1998, but it had been in use for a lot longer than that, and the ratification was primarily setting down current usage rather than imposing structure. And since C++ was based on C, and C has header files, C++ has them too.

嗯,C++ 于 1998 年获得批准,但它的使用时间比这长得多,批准主要是确定当前的使用情况,而不是强加结构。因为 C++ 是基于 C 的,而且 C 有头文件,所以 C++ 也有头文件。

The main reason for header files is to enable separate compilation of files, and minimize dependencies.

头文件的主要原因是启用文件的单独编译,并最大限度地减少依赖关系。

Say I have foo.cpp, and I want to use code from the bar.h/bar.cpp files.

假设我有 foo.cpp,我想使用 bar.h/bar.cpp 文件中的代码。

I can #include "bar.h" in foo.cpp, and then program and compile foo.cpp even if bar.cpp doesn't exist. The header file acts as a promise to the compiler that the classes/functions in bar.h will exist at run-time, and it has everything it needs to know already.

我可以在 foo.cpp 中 #include "bar.h",然后编程和编译 foo.cpp,即使 bar.cpp 不存在。头文件向编译器承诺 bar.h 中的类/函数将在运行时存在,并且它已经拥有它需要知道的一切。

Of course, if the functions in bar.h don't have bodies when I try to link my program, then it won't link and I'll get an error.

当然,如果当我尝试链接我的程序时 bar.h 中的函数没有主体,那么它不会链接并且我会收到错误消息。

A side-effect is that you can give users a header file without revealing your source code.

一个副作用是您可以在不泄露源代码的情况下为用户提供头文件。

Another is that if you change the implementation of your code in the *.cpp file, but do not change the header at all, you only need to compile the *.cpp file instead of everything that uses it. Of course, if you put a lot of implementation into the header file, then this becomes less useful.

另一个是,如果您更改了 *.cpp 文件中代码的实现,但根本不更改标头,则只需编译 *.cpp 文件而不是使用它的所有内容。当然,如果你把大量的实现放到头文件中,那么这就没那么有用了。

回答by Alex Rodrigues

It doesn't need a separate header file with the same functions as in main. It only needs it if you develop an application using multiple code files and if you use a function that was not previously declared.

它不需要与 main 具有相同功能的单独头文件。仅当您使用多个代码文件开发应用程序并且使用先前未声明的函数时才需要它。

It's really a scope problem.

这确实是一个范围问题。

回答by Diaa Sami

C++ was ratified in 1998, so why is it designed this way? What advantages does having a separate header file have?

C++ 是在 1998 年批准的,那么为什么它是这样设计的呢?单独的头文件有什么好处?

Actually header files become very useful when examining programs for the first time, checking out header files(using only a text editor) gives you an overview of the architecture of the program, unlike other languages where you have to use sophisticated tools to view classes and their member functions.

实际上头文件在第一次检查程序时变得非常有用,检查头文件(仅使用文本编辑器)可以让您大致了解程序的体系结构,这与其他语言不同,您必须使用复杂的工具来查看类和他们的成员函数。