静态、非成员或静态非成员函数
Static, nonmember or static nonmember function?
每次我有一些功能是在"实用"的方向,我最终想知道哪个选项是最好的。例如,打印消息结构(自己的或外部的),一些编码/解码代码或只是一些有用的转换函数在我正在工作的上下文中。
我考虑的选项是:
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;
}
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 将公共但非静态的成员函数与ALGLIB集成
- 私有类型的静态常量成员
- 如何在C++中使用非静态成员函数作为回调函数
- (C++)为什么静态成员可以在初始化之前使用
- 添加静态constexpr成员是否会更改结构/类的内存映射
- 静态数据成员模板专用化的实例化点在哪里
- 在派生类中绑定非静态模板化成员函数
- 类的全局对象和静态成员
- 在作为静态成员包含在另一个类中的类的构造函数中使用 cout
- 模板化类中静态成员的延迟初始化
- 枚举成员与静态 int 成员?
- 使用静态成员声明类时遇到问题
- C++ 模板类型的静态 lambda 成员的构造
- 初始化与类类型相同的静态成员(静态初始化顺序问题)
- 成员静态回调函数的外部"C"
- 成员静态函数中的C++静态变量
- 将pthread_mutex_t和pthread_cond_t作为类成员静态变量的任何缺点
- 初始化私有成员静态常量数组