好吧,无论如何都不是 C/C++ 专家,但我认为头文件的重点是声明函数,然后 C/CPP 文件是定义实现。
头文件的真正目的是在多个源文件之间共享代码。它通常用于将声明与实现分开以获得更好的代码管理,但这不是必需的。可以编写不依赖于头文件的代码,也可以编写仅由头文件组成的代码(STL 和 Boost 库就是很好的例子)。请记住,当预处理器遇到#include
语句时,它会将语句替换为被引用文件的内容,然后编译器只看到完成的预处理代码。
因此,例如,如果您有以下文件:
富.h:
#ifndef FooH
#define FooH
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
#endif
Foo.cpp:
#include "Foo.h"
UInt32 Foo::GetNumberChannels() const
{
return _numberChannels;
}
酒吧.cpp:
#include "Foo.h"
Foo f;
UInt32 chans = f.GetNumberChannels();
预处理器分别解析 Foo.cpp 和 Bar.cpp 并生成编译器随后解析的以下代码:
Foo.cpp:
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
UInt32 Foo::GetNumberChannels() const
{
return _numberChannels;
}
酒吧.cpp:
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
Foo f;
UInt32 chans = f.GetNumberChannels();
Bar.cpp 编译成 Bar.obj 并包含调用 into 的引用Foo::GetNumberChannels()
。Foo.cpp 编译成 Foo.obj 并包含Foo::GetNumberChannels()
. 编译后,链接器将匹配 .obj 文件并将它们链接在一起以生成最终的可执行文件。
那么为什么在标头中有实现呢?
通过在方法声明中包含方法实现,它被隐式声明为内联(也inline
可以显式使用一个实际关键字)。指出编译器应该内联一个函数只是一个提示,并不能保证该函数实际上会被内联。但如果是这样,那么无论从哪里调用内联函数,函数的内容都会直接复制到调用站点,而不是生成一个CALL
语句来跳转到函数并在退出时跳转回调用者。然后,编译器可以考虑周围的代码,并在可能的情况下进一步优化复制的代码。
它与 const 关键字有关吗?
不会。const
关键字仅向编译器表明该方法不会改变运行时正在调用的对象的状态。
与在 CPP 文件中定义实现相比,这样做的好处/要点是什么?
当有效使用时,它通常允许编译器生成更快和更好优化的机器代码。