为什么有头文件和.cpp文件? 为什么C++有头文件和.cpp文件?
这是声明接口的预处理器方式。将接口(方法声明)放入头文件,将实现放入cpp。使用库的应用程序只需要知道接口,通过接口可以访问它们。< p>因为在C++中,最终的可执行代码不携带任何符号信息,它或多或少是纯机器代码。为什么有头文件和.cpp文件? 为什么C++有头文件和.cpp文件?,c++,header-files,C++,Header Files,这是声明接口的预处理器方式。将接口(方法声明)放入头文件,将实现放入cpp。使用库的应用程序只需要知道接口,通过接口可以访问它们。< p>因为在C++中,最终的可执行代码不携带任何符号信息,它或多或少是纯机器代码。 因此,您需要一种与代码本身分离的方法来描述一段代码的接口。这个描述在头文件中。嗯,主要原因是将接口与实现分离。标头声明类(或正在实现的任何类)将执行“什么”,而cpp文件定义它将如何执行这些功能 这减少了依赖性,因此使用头的代码不一定需要知道实现的所有细节,也不需要知道实现所需的任何
因此,您需要一种与代码本身分离的方法来描述一段代码的接口。这个描述在头文件中。嗯,主要原因是将接口与实现分离。标头声明类(或正在实现的任何类)将执行“什么”,而cpp文件定义它将如何执行这些功能 这减少了依赖性,因此使用头的代码不一定需要知道实现的所有细节,也不需要知道实现所需的任何其他类/头。这将减少编译时间,以及在实现中发生更改时所需的重新编译量
它不是完美的,您通常会使用诸如的技术来正确地分离接口和实现,但这是一个良好的开端。因为设计库格式的人不想“浪费”空间来获取很少使用的信息,如C预处理器宏和函数声明 因为你需要这些信息来告诉你的编译器“这个函数在链接器工作的时候可以使用”,他们必须拿出第二个文件来存储这些共享信息
C/C++之后的大多数语言都将这些信息存储在输出中(例如Java字节码),或者它们根本不使用预编译格式,总是以源代码形式分发并动态编译(Python、Perl)。通常,您希望有一个接口定义,而不必发布整个代码。例如,如果您有一个共享库,您将附带一个头文件,它定义了共享库中使用的所有函数和符号。如果没有头文件,则需要发送源文件 在单个项目中,头文件IMHO至少用于两个目的:
- 清晰性,也就是说,通过将接口与实现分开,更容易阅读代码
- 编译时。通过尽可能只使用接口,而不是完整的实现,可以缩短编译时间,因为编译器可以简单地引用接口,而不必解析实际代码(理想情况下,只需要一次)
// A.CPP
void doSomething()
{
doSomethingElse(); // Defined in B.CPP
}
// B.CPP
void doSomethingElse()
{
// Etc.
}
// A.CPP
void doSomethingElse() ; // From B.CPP
void doSomething()
{
doSomethingElse() ; // Defined in B.CPP
}
它不会编译,因为A.CPP无法知道“doSomethingElse”的存在。。。除非a.CPP中有声明,如:
// A.CPP
void doSomething()
{
doSomethingElse(); // Defined in B.CPP
}
// B.CPP
void doSomethingElse()
{
// Etc.
}
// A.CPP
void doSomethingElse() ; // From B.CPP
void doSomething()
{
doSomethingElse() ; // Defined in B.CPP
}
然后,如果您有使用相同符号的C.CPP,则可以复制/粘贴声明
复制/粘贴警报!
是的,有个问题。复制/粘贴是危险的,并且很难维护。这意味着,如果我们有办法不复制/粘贴,并且仍然声明符号,那就太酷了。。。我们怎么做?包括一些文本文件,通常由h,.h,.h,+,或,我的首选C++文件,.HPP:< /P>后缀。
// B.HPP (here, we decided to declare every symbol defined in B.CPP)
void doSomethingElse() ;
// A.CPP
#include "B.HPP"
void doSomething()
{
doSomethingElse() ; // Defined in B.CPP
}
// B.CPP
#include "B.HPP"
void doSomethingElse()
{
// Etc.
}
// C.CPP
#include "B.HPP"
void doSomethingAgain()
{
doSomethingElse() ; // Defined in B.CPP
}
如何包含
工作?
包括一个文件,本质上,将解析并复制它的内容粘贴到CPP文件中
例如,在以下代码中,使用A.HPP标头:
// A.HPP
void someFunction();
void someOtherFunction();
。。。来源B.CPP:
// B.CPP
#include "A.HPP"
void doSomething()
{
// Etc.
}
。。。纳入后将成为:
// B.CPP
void someFunction();
void someOtherFunction();
void doSomething()
{
// Etc.
}
一件小事——为什么要将B.HPP包括在B.CPP中?
在当前情况下,这是不需要的,B.HPP有doSomethingElse
函数声明,B.CPP有doSomethingElse
函数定义(其本身就是一个声明)。但在更一般的情况下,B.HPP用于声明(和内联代码),可能没有相应的定义(例如,枚举、普通结构等),因此如果B.CPP使用来自B.HPP的声明,则可能需要include。总而言之,默认情况下,源文件包含其标题是“很有品味的”
结论
头文件是必要的,因为C++编译器不能单独搜索符号声明,因此,必须通过包含这些声明来帮助它。 最后一句话:您应该在HPP文件的内容周围设置标题保护,以确保多个包含不会破坏任何内容,但总而言之,我相信HPP文件存在的主要原因已在上面解释
#ifndef B_HPP_
#define B_HPP_
// The declarations in the B.hpp file
#endif // B_HPP_
甚至更简单(虽然不是标准)
因为C,这个概念的起源,已经有30年的历史了,而在当时,它是将多个文件中的代码链接在一起的唯一可行的方法
今天,这是一个可怕的黑客,它完全破坏C++中编译时间,导致无数的不必要的依赖(因为头文件中的类定义暴露了太多关于实现的信息),等等。
< P>因为C++从C继承了它们。不幸的是, < P>响应, 这减少了依赖性,因此使用标头的代码不会