我有一个在头文件中声明和实现的 C++ 类。我选择这一点是因为由于
_GLIBCXX_DEBUG
和预编译库,人们无法轻松地在调试和发布版本之间移动。例如,如果我定义 _GLIBCXX_DEBUG
,Boost 将由于源文件中的 ABI 更改而崩溃。
仅标头实现会产生重复符号的问题。例如,在下面的类中
operator==
和非成员 swap
将产生多重定义的符号。
// Foo.hpp
namespace Bar
{
template
class Foo
{
...
};
bool operator==(const Foo& a, const Foo& b) {
..
}
}
namespace std
{
template <>
void swap(Bar::Foo& a, Bar::Foo& b)
{
a.swap(b);
}
}
当声明和实现分离时,文件(Foo.hpp和Foo.cpp)编译并链接正常。
让它正确编译和链接的技巧是什么?
inline bool operator==(const Foo& a, const Foo& b) {
..
}
成员函数是隐式内联的,只要它们是在类内部定义的。同样的事情对它们来说也是如此:如果它们可以毫不费力地放入标题中,那么您确实可以这样做。
因为函数的代码放在头文件中并且可见,所以编译器能够对它们进行内联调用,即将函数的代码直接放在调用处(不是因为你在它前面放了内联,而是更多是因为编译器决定这样做,不过,仅内联是对编译器的一个提示)。这可以提高性能,因为编译器现在可以看到参数在哪里与函数的本地变量匹配,以及参数在哪里不会互相别名 - 最后但并非最不重要的一点是,不再需要函数框架分配。