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.CPP 无法知道“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.CPP 中包含 B.HPP?
在当前情况下,这不是必需的,B.HPP 有doSomethingElse函数声明,B.CPP 有doSomethingElse函数定义(它本身就是一个声明)。但在更一般的情况下,B.HPP 用于声明(和内联代码),可能没有相应的定义(例如,枚举、普通结构等),因此如果 B.CPP 可能需要包含使用 B.HPP 的那些声明。总而言之,默认情况下包含其标题的源是“好品味”。
结论
因此头文件是必要的,因为 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
岸边的意思、解释和含义口袋妖怪游戏哪个好玩