为什么c++有头文件和。cpp文件?
当前回答
c++编译
c++中的编译分为两个主要阶段:
第一种是将“源”文本文件编译为二进制“对象”文件:CPP文件是编译后的文件,编译时不了解其他CPP文件(甚至库),除非通过原始声明或头包含提供给它。CPP文件通常被编译成. obj或. o“对象”文件。 第二步是将所有“目标”文件链接在一起,从而创建最终的二进制文件(库或可执行文件)。
HPP在整个过程中处于什么位置?
一个可怜孤独的CPP文件…
每个CPP文件的编译都独立于所有其他CPP文件,这意味着如果a .CPP需要在B.CPP中定义的符号,例如:
// A.CPP
void doSomething()
{
doSomethingElse(); // Defined in B.CPP
}
// B.CPP
void doSomethingElse()
{
// Etc.
}
它不会编译,因为a.c p没有办法知道“doSomethingElse”的存在…除非a . cpp中有声明,比如:
// A.CPP
void doSomethingElse() ; // From B.CPP
void doSomething()
{
doSomethingElse() ; // Defined in B.CPP
}
然后,如果你有使用相同符号的C.CPP,然后复制/粘贴声明…
复制/粘贴警报!
是的,有个问题。复制/粘贴是危险的,并且难以维护。这意味着如果我们有一些不复制/粘贴的方法,并且仍然声明符号将会很酷…我们该怎么做呢?通过包含一些文本文件,通常以.h, .hxx, .h++或,我更喜欢的c++文件,.hpp结尾:
// 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
}
include是如何工作的?
从本质上讲,包含一个文件将解析并将其内容复制粘贴到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.h ppp包括在b.c cpp中?
In the current case, this is not needed, and B.HPP has the doSomethingElse function declaration, and B.CPP has the doSomethingElse function definition (which is, by itself a declaration). But in a more general case, where B.HPP is used for declarations (and inline code), there could be no corresponding definition (for example, enums, plain structs, etc.), so the include could be needed if B.CPP uses those declaration from B.HPP. All in all, it is "good taste" for a source to include by default its header.
结论
因此,头文件是必要的,因为c++编译器不能单独搜索符号声明,因此,您必须通过包含这些声明来帮助它。
最后一句话:你应该在你的HPP文件的内容周围设置头保护,以确保多个包含不会破坏任何东西,但总而言之,我相信HPP文件存在的主要原因已经在上面解释过了。
#ifndef B_HPP_
#define B_HPP_
// The declarations in the B.hpp file
#endif // B_HPP_
或者更简单(尽管不是标准)
#pragma once
// The declarations in the B.hpp file
其他回答
回应MadKeithV的回答,
这减少了依赖关系,因此使用标头的代码不会 必然需要知道实现的所有细节和任何 其他类/头只需要这样做。这将减少 编译次数,以及需要的重新编译量 实现中的某些内容发生了变化。
另一个原因是头文件为每个类提供了唯一的id。
如果我们有
class A {..};
class B : public A {...};
class C {
include A.cpp;
include B.cpp;
.....
};
我们会有错误,当我们试图构建项目时,因为A是B的一部分,有了头文件,我们就可以避免这种头痛……
主要原因是将接口从实现中分离出来。头文件声明了一个类(或任何正在实现的类)将做什么,而cpp文件定义了它将“如何”执行这些功能。
这减少了依赖关系,因此使用头文件的代码不一定需要知道实现的所有细节,也不需要知道为此所需的任何其他类/头文件。这将减少编译时间,以及当实现中的某些内容发生更改时所需的重新编译量。
它并不完美,您通常会求助于诸如Pimpl Idiom之类的技术来正确地分离接口和实现,但这是一个良好的开端。
因为设计库格式的人不想为很少使用的信息(如C预处理器宏和函数声明)“浪费”空间。
因为你需要这些信息来告诉你的编译器“当链接器完成它的工作时,这个函数稍后可用”,他们必须拿出第二个文件来存储这些共享信息。
C/ c++之后的大多数语言将这些信息存储在输出中(例如Java字节码),或者它们根本不使用预编译的格式,总是以源代码形式分发并动态编译(Python, Perl)。
c++编译
c++中的编译分为两个主要阶段:
第一种是将“源”文本文件编译为二进制“对象”文件:CPP文件是编译后的文件,编译时不了解其他CPP文件(甚至库),除非通过原始声明或头包含提供给它。CPP文件通常被编译成. obj或. o“对象”文件。 第二步是将所有“目标”文件链接在一起,从而创建最终的二进制文件(库或可执行文件)。
HPP在整个过程中处于什么位置?
一个可怜孤独的CPP文件…
每个CPP文件的编译都独立于所有其他CPP文件,这意味着如果a .CPP需要在B.CPP中定义的符号,例如:
// A.CPP
void doSomething()
{
doSomethingElse(); // Defined in B.CPP
}
// B.CPP
void doSomethingElse()
{
// Etc.
}
它不会编译,因为a.c p没有办法知道“doSomethingElse”的存在…除非a . cpp中有声明,比如:
// A.CPP
void doSomethingElse() ; // From B.CPP
void doSomething()
{
doSomethingElse() ; // Defined in B.CPP
}
然后,如果你有使用相同符号的C.CPP,然后复制/粘贴声明…
复制/粘贴警报!
是的,有个问题。复制/粘贴是危险的,并且难以维护。这意味着如果我们有一些不复制/粘贴的方法,并且仍然声明符号将会很酷…我们该怎么做呢?通过包含一些文本文件,通常以.h, .hxx, .h++或,我更喜欢的c++文件,.hpp结尾:
// 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
}
include是如何工作的?
从本质上讲,包含一个文件将解析并将其内容复制粘贴到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.h ppp包括在b.c cpp中?
In the current case, this is not needed, and B.HPP has the doSomethingElse function declaration, and B.CPP has the doSomethingElse function definition (which is, by itself a declaration). But in a more general case, where B.HPP is used for declarations (and inline code), there could be no corresponding definition (for example, enums, plain structs, etc.), so the include could be needed if B.CPP uses those declaration from B.HPP. All in all, it is "good taste" for a source to include by default its header.
结论
因此,头文件是必要的,因为c++编译器不能单独搜索符号声明,因此,您必须通过包含这些声明来帮助它。
最后一句话:你应该在你的HPP文件的内容周围设置头保护,以确保多个包含不会破坏任何东西,但总而言之,我相信HPP文件存在的主要原因已经在上面解释过了。
#ifndef B_HPP_
#define B_HPP_
// The declarations in the B.hpp file
#endif // B_HPP_
或者更简单(尽管不是标准)
#pragma once
// The declarations in the B.hpp file
因为在c++中,最终的可执行代码不携带任何符号信息,它或多或少是纯机器代码。
因此,您需要一种方法来描述一段代码的接口,这种方法与代码本身是分开的。该描述在头文件中。
推荐文章
- 为什么我的程序不能在Windows 7下用法语编译?
- 如何获取变量的类型?
- 什么是奇怪的重复模板模式(CRTP)?
- 连接两个向量的最佳方法是什么?
- 在c++中,是通过值传递更好,还是通过引用到const传递更好?
- 在STL中deque到底是什么?
- Windows上最好的免费c++分析器是什么?
- 如何自动转换强类型枚举为int?
- 在一个类中使用具有成员函数的泛型std::function对象
- 'for'循环中的后增量和前增量产生相同的输出
- 虚函数和纯虚函数的区别
- c++中的_tmain()和main()有什么区别?
- 内存泄漏是否正常?
- 当启用c++ 11时,std::vector性能回归
- 什么时候使用哪种指针?