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