15

在阅读了 sbi 和 Eli Bendersky 在这个问题中的答案后,我开始想知道静态成员函数的用途。

一个类的无好友函数不应该做任何静态成员函数可以做的事情吗?如果是这样,为什么/什么时候我应该更喜欢静态成员函数而不是免费的朋友?

4

5 回答 5

13

一般来说:

需要访问私有成员

静态成员函数可以访问类的私有成员。如果需要,可以使用静态成员函数。无论如何,您必须在标头中声明它以授予它访问权限,因此您不妨将其设为成员而不是朋友。对于具有 getInstance() 方法作为单例的单例,以及使用静态工厂方法 createInstance() 以确保它们在堆上创建的类,通常采用这种方式。这两个都需要访问私有构造函数。

元编程

静态成员函数非常适合模板元编程,您可以在其中传入一个类并调用其方法,而无需知道在调用点实际会调用哪个函数。这通常称为“编译时多态性”,是元编程的重要组成部分。std::char_traits 就是基于这个原则。

禁止进入

私有静态成员函数的普遍使用,只是为了它只能被类访问,并且本身不需要访问私有成员,这不是一个很好的使用静态成员函数,因为它是实现细节的一部分类,最好在编译单元的匿名命名空间中完成。

但是,如果静态成员函数受到保护,它就可以使用,因为它可以被派生类调用,但不能被外部类调用。

朋友功能

  • 可以访问私有成员,但无论如何都需要在标头中声明。
  • 可以在元编程中作为“重载”的一部分使用,但仍需要在标头中声明。(常见的例子是operator<<
  • 不适用于有友谊的受保护访问,因为您在这里尝试做的是限制对该方法的访问,而不是调用可以访问的内容。
于 2011-01-18T11:09:17.393 回答
12

静态方法:

  • 在类创建的“命名空间”中提供封装。如果你的类是Animal并且静态方法是Create,你必须用Animal::Create. 这比全局函数更好,并且允许以相对自然的语法实现工厂和“虚拟构造函数”。
  • 可以访问静态成员。这样的成员在某些情况下很有用,如果没有静态方法和成员,您将不得不使用全局变量和函数。
于 2011-01-18T10:54:12.787 回答
4

通常,坦率地说,你不应该这样做。免费功能被大大低估了。

您从使用静态成员中获得的隐式“命名空间”(假设该类只不过是静态成员的命名空间,这是真的)是我能想到的唯一好处。

如果静态函数成员需要持久变量,那么拥有静态数据成员的能力也可能很有用。

于 2011-01-18T10:49:35.970 回答
3

有些人对使用静态函数持谨慎态度,因为那些来自过程背景且不了解 OO 的人经常使用它。

然而,有许多设计模式可以使用静态成员函数来实现

例如。单例模式和工厂模式是我最头疼的几个,实际上大多数需要创建对象的结构模式都需要静态成员函数。

于 2011-01-18T10:54:36.403 回答
1

static正如您正确识别的那样,成员函数没有附加值。更糟糕的是,当用于实现细节时,这会引入额外的依赖项(在编译方面)。

唯一不能用匿名自由函数模拟的用途是访问protected,即访问父静态函数的派生类。但是,这从来都不是必需的:您可以将其设为常规成员函数(我假设您没有全局状态,否则静态/朋友的区别不是直接关注的问题)。

模板元编程中函数的使用static已经被唤起......然而它与内部类型问题非常相似:它使得很难提供默认版本。另一方面,适当定义的自由函数(将类型作为指针)可以提出模板版本:

struct some_traits
{
  static void doStuff();
};

// versus

struct some_traits {};

void doStuff(some_traits*);

// and the default: void doStuff(...);

当然,当成员函数为用户提供更多灵活性时,为什么这应该是一个静态函数总是存在的问题。为此,我将引用标准委员会在Allocator概念上所做的举动:现在授权有状态分配器,这使我们有机会将给定的节点打包map在同一页面中,而不是将它们分散到整个堆中。

最后是接口问题。然而,自从 Sutter 提倡一个类和定义在同一个头文件中的自由函数都构成这个类的公共接口 => 这就是 ADL 的用途以来,已经有很长时间了!因此,与其说是“良好实践”,不如说是安慰古代 OO 程序员。

真的,我看不出使用static成员函数有什么好处。我希望人们会提出相反的想法来提出真实的案例。

于 2011-01-18T16:16:41.447 回答