Amb*_*ber 105
头文件(.h
)旨在提供多个文件中所需的信息.类声明,函数原型和枚举等内容通常都在头文件中.总之,"定义".
代码文件(.cpp
)旨在提供只需要在一个文件中知道的实现信息.通常,函数体和应该/将永远不会被其他模块访问的内部变量属于.cpp
文件.总之,"实施".
最简单的问题就是要问自己确定哪些属于哪个"如果我改变了这个,我是否必须更改其他文件中的代码才能重新编译?" 如果答案是"是",它可能属于头文件; 如果答案是"否",它可能属于代码文件.
pae*_*bal 51
事实上,在C++中,这比C头/源组织稍微复杂一些.
编译器会看到一个大的源(.cpp)文件及其正确包含的标头.源文件是将编译为目标文件的编译单元.
因为一个编译单元可能需要有关另一个编译单元中的实现的信息.因此,可以在一个源中编写一个函数的实现,并在需要使用它的另一个源中编写该函数的声明.
在这种情况下,有两个相同信息的副本.这是邪恶的......
解决方案是分享一些细节.虽然实现应该保留在Source中,但是共享符号的声明,如函数,结构,类,枚举等的定义,可能需要共享.
标头用于放置这些共享细节.
将标题移动到多个源之间需要共享的声明
在C++中,还有一些其他东西可以放在标题中,因为它们也需要共享:
移动到标题所有需要共享的内容,包括共享实现
是.事实上,有很多不同的东西可以在"标题"内(即在源之间共享).
它变得复杂,在某些情况下(符号之间的循环依赖),不可能将它保存在一个标题中.
这意味着,在极端情况下,您可以:
让我们假设我们有一个模板化的MyObject.我们可以有:
// - - - - MyObject_forward.hpp - - - -
// This header is included by the code which need to know MyObject
// does exist, but nothing more.
template<typename T>
class MyObject ;
Run Code Online (Sandbox Code Playgroud)
.
// - - - - MyObject_declaration.hpp - - - -
// This header is included by the code which need to know how
// MyObject is defined, but nothing more.
#include <MyObject_forward.hpp>
template<typename T>
class MyObject
{
public :
MyObject() ;
// Etc.
} ;
void doSomething() ;
Run Code Online (Sandbox Code Playgroud)
.
// - - - - MyObject_implementation.hpp - - - -
// This header is included by the code which need to see
// the implementation of the methods/functions of MyObject,
// but nothing more.
#include <MyObject_declaration.hpp>
template<typename T>
MyObject<T>::MyObject()
{
doSomething() ;
}
// etc.
Run Code Online (Sandbox Code Playgroud)
.
// - - - - MyObject_source.cpp - - - -
// This source will have implementation that does not need to
// be shared, which, for templated code, usually means nothing...
#include <MyObject_implementation.hpp>
void doSomething()
{
// etc.
} ;
// etc.
Run Code Online (Sandbox Code Playgroud)
在"现实生活"中,它通常不那么复杂.大多数代码只有一个简单的头/源组织,源代码中有一些内联代码.
但在其他情况下(模板对象知道彼此),我必须为每个对象分别声明和实现标头,包含这些标头的空源只是为了帮助我看到一些编译错误.
将标头分解为单独标头的另一个原因可能是加速编译,将解析的符号数量限制为严格必要,并避免在内联方法实现发生更改时仅关注前向声明的源的不必要的重新编译.
您应该使代码组织尽可能简单,并尽可能模块化.尽可能多地放在源文件中.仅在标题中公开需要共享的内容.
但是,如果您的代码组织变得比普通的头/源组织更"有趣",那么在模板化对象之间存在循环依赖的那一天也不要感到惊讶......
^ _ ^
Adr*_*son 16
除了所有其他答案,我会告诉你你不要放在头文件中:
using
声明(最常见的是using namespace std;
)不应该出现在头文件中,因为它们会污染包含它的源文件的命名空间.
什么编译成零(零二进制足迹)进入头文件.
变量不会编译成任何东西,但是类型声明会这样做(因为它们只描述了变量的行为).
函数没有,但内联函数做(或宏),因为它们只在被调用的地方产生代码.
模板不是代码,它们只是创建代码的秘诀.所以他们也进入h档案.
小智 5
通常,您将声明放在头文件中,将定义放在实现 (.cpp) 文件中。模板是个例外,其中的定义也必须放在标题中。
这个问题和类似的问题在 SO 上经常被问到 - 请参阅Why have header files and .cpp files in C++? 和C++ 头文件,例如代码分离。