静态,非成员或静态非成员函数?

mur*_*att 8 c++ static non-member-functions

每当我有一些朝向"效用"方向的功能时,我最终想知道哪个选项是最好的.例如,在我工作的上下文中打印消息结构(自己的或外部的),一些编码/解码代码或简单的一些有用的转换函数.

我想到的选项是:

1)helper类/ struct中的静态函数.

struct helper
{
    static bool doSomething(...);
};
Run Code Online (Sandbox Code Playgroud)

2)非成员函数.

namespace helper
{
    bool doSomething(...);
}
Run Code Online (Sandbox Code Playgroud)

3)静态非成员函数.

namespace helper
{
    static bool doSomething(...);
}
Run Code Online (Sandbox Code Playgroud)

在某些情况下,可能需要在"实用程序"中初始化或保持状态,因此我选择选项1以避免"全局"状态.但是,如果没有需要保留的状态,我应该选择2还是3?选项2和3之间的实际区别是什么?

重要的是要考虑什么,是否有一种首选的方法来解决这个问题?谢谢!

Dav*_*eas 12

选项2和3之间的区别在于,在第二种情况下,该功能将在翻译单元内部.如果函数只在cpp中定义,那么它应该是一个选项(大致相当于一个未命名命名空间 - 这是第四个要考虑的选项,大致相当于3).

如果该函数由不同的翻译单元使用,那么你应该使用选项2.该函数将被编译一次(除非你将其标记为inline并在标题中提供定义),而使用选项3,编译器将创建它是一个每个翻译单元的内部副本.

从选项1开始,我会避免它.在Java或C#中,您被迫在任何地方使用类,并且当操作不能很好地映射到对象范例时,您最终会得到实用程序类.另一方面,在C++中,您可以将这些操作作为独立功能提供,而无需添加额外的层.如果您选择实用程序类,请不要忘记禁用对象的创建.

函数是在类还是名称空间级别将影响查找,这将影响用户代码.除非您在类范围内,否则静态成员函数需要始终使用类名进行限定,而将命名空间函数放入范围则有不同的方法.作为一个说明性的例子,考虑一堆数学助手函数,并调用代码:

double do_maths( double x ) {
   using namespace math;
   return my_sqrt( x ) * cube_root(x);
}
// alternatively with an utility class:
double do_maths( double x ) {
   return math::my_sqrt(x) * math::cube_root(x);
}
Run Code Online (Sandbox Code Playgroud)

你发现哪一个更容易阅读是一个不同的故事,但我更喜欢前者:在函数中我可以选择命名空间然后只关注操作并忽略查找问题.


Ale*_* C. 8

不要将类用作命名空间.在命名空间内使用免费(即非成员)函数是最简单的事情.

此外,如果必须跨多个翻译单元使用该功能,则该功能不应是静态的.否则,它将被复制.

使用类作为命名空间是愚蠢的:为什么要创建一个你不会实例化的类?

如果要保留某个状态,则在某处具有全局状态:函数内部的静态变量,实用程序全局对象(可能在"私有"命名空间中,或者作为一个翻译单元中的静态全局变量).不要写你没有实例化的类.

唉,具有C#/ Java背景的人习惯于做这个愚蠢的事情,但这是因为他们的语言设计者单方面决定自由功能是邪恶的.他们是否应该被枪杀是宗教问题.

最后要提醒的是:全球国家应该很少使用.实际上,它将代码与代码增长时无法控制的方式耦合到全局状态的存在.你应该总是问自己为什么不明确这种耦合.