当前,我希望在头文件中具有全局函数。我发现了三种可能的实现方式(可能还有更多)。第一个是拥有一个具有公共静态函数的类:
class foo {
public:
static void bar() {
...
}
};
第二个是要具有内联全局函数:
inline void bar() {
...
}
第三种是使用C样式的静态头函数:
static void bar() {
...
}
我想知道是否有一种普遍接受的在头文件中包含全局函数的正确方法,以及上述方法的优点和缺点是什么。
第一种方法的替代方法(类中的static
成员函数)是使用命名的名称空间:
namespace foo {
inline void bar () {
...
}
}
如果类foo
的每个成员都是静态的,使用命名空间方法可能会更好,因为命名空间方法(namespace foo
)可以更好地显示意图。
最后一种方法的替代方法(使用C样式的静态函数)是使用匿名名称空间:
namespace {
void bar () {
...
}
}
这两种方法(C样式的静态函数与匿名名称空间中的哪一种)更好,这是一个意见问题。在C ++ 11之前,不建议在命名空间范围(包括全局命名空间)中使用static
。
所以现在我们有五种方法,而不是问题中列出的三种。
将函数设为inline
(您的前两个选项,加上我的命名空间方法)意味着在可执行文件中最多会有一个函数定义。 inline
关键字对实现的弱提示是,它应考虑在调用函数的位置内联扩展有问题的函数。另一方面,inline
关键字对于有关一个定义规则的实现是非常强大的命令。在这种情况下,inline
的意思是对实现的承诺是,尽管在不同的翻译单元中可能有多个定义,但是这些定义中的每一个都是彼此的精确重复。
如果使用的是编译器和链接器,则编译器可能会拒绝服从inline
提示,而是离线定义函数。该脱机定义对于链接器将是可见的。链接器会将不同翻译单元中的多个定义剔除为生成的可执行文件中的一个定义。
假设您的函数定义涉及宏,则宏的扩展在一个翻译单元与另一个翻译单元之间是不同的。或者假设您已经编译了使用相同功能且处于不同优化级别的不同翻译单元,从而使函数的编译版本在不同翻译单元中有所不同。无论哪种方式,您都无法兑现实现的承诺,即跨翻译单元的功能的多个定义确实是相同的。不需要实现来检查这一点,“不需要诊断”。该实现将任意选择这些定义之一作为将在整个可执行文件中使用的一种定义。
设置函数static
(通过您的第三个选项显式或通过我的匿名名称空间选项隐式)使链接程序隐藏了该定义。如果您在多个翻译单元中使用该功能,则可执行文件将具有实质上相同功能的多种实现。
使用内部链接方法(C样式的静态函数或匿名名称空间)避免了上述问题,因为在此,“一个定义规则”适用于翻译单元级别而不是可执行文件级别。此方法对于确保一个翻译单元使用功能的高度优化版本而另一翻译单元使用同一功能的非优化,调试友好版本很有用。如果所有定义确实都相同,则缺点是可执行文件过大。