静态、非成员或静态非成员函数

Static, nonmember or static nonmember function?

本文关键字:成员 静态 函数      更新时间:2023-10-16

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

我考虑的选项是:

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

struct helper
{
    static bool doSomething(...);
};
2)非成员函数
namespace helper
{
    bool doSomething(...);
}
3)静态非成员函数
namespace helper
{
    static bool doSomething(...);
}

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

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

选项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);
}

哪一个更容易阅读是另一回事,但我更喜欢前者:在函数中,我可以选择名称空间,然后只关注操作,忽略查找问题。

不要使用类作为命名空间。使用免费(即。命名空间内的非成员)函数是最简单的

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

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

如果要保留某些状态,那么在某个地方拥有一个全局状态:函数内部的静态变量,实用程序全局对象(可能在"私有"命名空间中,或者作为您的翻译单元中的一个静态全局变量)。不要编写没有实例化的类。

唉,有c#/Java背景的人习惯于做这种愚蠢的事情,但这是因为他们的语言设计者单方面地决定自由函数是邪恶的。他们该不该被枪毙是宗教问题。

作为最后的警告:应该很少使用全局状态。实际上,当代码增长时,它以一种您无法控制的方式将您的代码与全局状态的存在耦合起来。您应该经常问自己,为什么不让这种耦合显式。

我在静态函数中使用struct,因为它在名称空间中提供了比非成员函数稍好的隔离(由于避免了Koenig查找)。

给一个我想避免的事情的例子:

namespace Foo
{
      struct A
      {
      };
      void f(const A& a) {}
}
void f(const Foo:A& a) { std::cout << "AAA"; }
int main(void)
{
      Foo::A a;
      f(a); // calls Foo:f
      return 0;
}