我从未真正理解为什么c++需要一个单独的头文件,其中包含与.cpp文件中相同的函数。它使得创建类和重构类变得非常困难,并且给项目添加了不必要的文件。还有一个必须包含头文件的问题,但是必须显式地检查它是否已经被包含。
c++在1998年被批准,那么为什么要这样设计呢?使用单独的头文件有什么好处?
后续问题:
当我所包含的是.h文件时,编译器如何找到其中的代码的.cpp文件?它是假定.cpp文件与.h文件具有相同的名称,还是实际上遍历目录树中的所有文件?
我从未真正理解为什么c++需要一个单独的头文件,其中包含与.cpp文件中相同的函数。它使得创建类和重构类变得非常困难,并且给项目添加了不必要的文件。还有一个必须包含头文件的问题,但是必须显式地检查它是否已经被包含。
c++在1998年被批准,那么为什么要这样设计呢?使用单独的头文件有什么好处?
后续问题:
当我所包含的是.h文件时,编译器如何找到其中的代码的.cpp文件?它是假定.cpp文件与.h文件具有相同的名称,还是实际上遍历目录树中的所有文件?
当前回答
你可以在没有头文件的情况下完美地开发c++。事实上,一些大量使用模板的库并不使用头文件/代码文件范例(参见boost)。但是在C/ c++中,你不能使用没有声明的东西。一个实用的方法 处理这个问题的方法就是使用头文件。此外,您还可以在不共享代码/实现的情况下共享接口。我认为这不是C语言的创造者所能想象到的:当你使用共享头文件时,你必须使用著名的:
#ifndef MY_HEADER_SWEET_GUARDIAN
#define MY_HEADER_SWEET_GUARDIAN
// [...]
// my header
// [...]
#endif // MY_HEADER_SWEET_GUARDIAN
这并不是真正的语言特性,而是处理多重包含的一种实用方法。
所以,我认为在创建C时,前向声明的问题被低估了,现在当使用像c++这样的高级语言时,我们必须处理这类事情。
对于我们这些可怜的c++用户来说,这又是一个负担……
其他回答
头文件的需求源于编译器在了解其他模块中的函数和(或)变量的类型信息方面的限制。编译后的程序或库不包含编译器绑定到其他编译单元中定义的任何对象所需的类型信息。
为了弥补这一限制,C和c++允许声明,并且可以在预处理器的#include指令的帮助下将这些声明包含到使用它们的模块中。
另一方面,像Java或c#这样的语言在编译器的输出(类文件或程序集)中包含了绑定所必需的信息。因此,不再需要维护模块的客户端所包含的独立声明。
编译器输出中没有包含绑定信息的原因很简单:在运行时不需要绑定信息(任何类型检查都发生在编译时)。这只会浪费空间。请记住,C/ c++来自于一个可执行文件或库的大小相当重要的时代。
如果你想让编译器自动找到其他文件中定义的符号,你需要强迫程序员把这些文件放在预定义的位置(就像Java包的结构决定了项目的文件夹结构)。我更喜欢头文件。此外,你还需要你所使用的库的源代码,或者一些统一的方法来把编译器需要的信息放在二进制文件中。
你可以在没有头文件的情况下完美地开发c++。事实上,一些大量使用模板的库并不使用头文件/代码文件范例(参见boost)。但是在C/ c++中,你不能使用没有声明的东西。一个实用的方法 处理这个问题的方法就是使用头文件。此外,您还可以在不共享代码/实现的情况下共享接口。我认为这不是C语言的创造者所能想象到的:当你使用共享头文件时,你必须使用著名的:
#ifndef MY_HEADER_SWEET_GUARDIAN
#define MY_HEADER_SWEET_GUARDIAN
// [...]
// my header
// [...]
#endif // MY_HEADER_SWEET_GUARDIAN
这并不是真正的语言特性,而是处理多重包含的一种实用方法。
所以,我认为在创建C时,前向声明的问题被低估了,现在当使用像c++这样的高级语言时,我们必须处理这类事情。
对于我们这些可怜的c++用户来说,这又是一个负担……
您似乎在询问如何将定义与声明分开,尽管头文件还有其他用途。
答案是c++不“需要”这个。如果将所有内容都标记为内联(对于类定义中定义的成员函数来说,这是自动的),则不需要分离。你可以在头文件中定义一切。
你想分手的原因可能是:
改善构建时间。 在没有定义源的情况下链接到代码。 避免将所有内容标记为“内联”。
如果你更普遍的问题是,“为什么c++和Java不一样?”,那么我不得不问,“为什么你写c++而不是Java?”- p;
但是,更严重的是,c++编译器不能像javac那样直接进入另一个翻译单元,并找出如何使用它的符号。头文件需要向编译器声明在链接时它期望可用的内容。
所以#include是一个直接的文本替换。如果你在头文件中定义所有东西,预处理器最终会对项目中的每个源文件创建一个巨大的复制和粘贴,并将其提供给编译器。c++标准在1998年被批准的事实与此无关,这是c++的编译环境如此紧密地基于C的事实。
转换我的评论来回答你接下来的问题:
编译器如何找到包含代码的.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 .cpp file 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 .o files, or static or dynamic libraries, and the header in effect is a promise that the definitions of the functions will be in there somewhere.
我认为头文件背后的真正(历史)原因是使编译器开发人员更容易……但是,头文件确实有优势。 查看之前的帖子了解更多讨论…