何时使用“静态功能”?


24

好的,我已经了解了静态函数是什么,但是我仍然看不到为什么它们比私有成员函数更有用。这在这里可能是一个新奇的问题,但是为什么不只用静态函数代替所有私有成员函数呢?


1
那不是“用私有成员函数替换所有静态函数”吗?当前,您要说的是看不到静态方法的要点,然后继续问为什么我们不使用更多静态方法。

5
什么是“静态功能”?在C ++中,至少还有两方面的含义(看着C ++ 11个草案最后我,他们会删除的取消通知static限制功能的文件范围。
大卫·索恩利

从C / C ++中的文件范围静态无功能的意义上来说,您是指“静态功能”,还是“静态成员功能/方法”?差异很大!
Jan Hudec

@JanHudec:我认为,鉴于private member我们的存在,我们可以放心地假设OP正在询问OO概念,并且不了解文件范围静态信息。
Matthieu M.

@MatthieuM .:实际上,“私人成员”的存在正是使我相信他确实是C ++意义上的静态函数的原因。因为文件作用域的静态函数和私有成员函数是在C ++中具有非常相似用法的两件事,所以用私有非静态成员替换public static成员没有多大意义。不幸的是,OP似乎没有响应。
Jan Hudec

Answers:


24

假设您使用的是OOP,则在不依赖任何类成员的情况下使用静态函数。它们仍然可以是私有的,但是由于不依赖于相关对象的任何实例,因此可以对它们进行优化。

除了上述内容之外,当您不想创建对象实例以仅在其上执行一个公共功能时,我发现静态函数很有用。对于包含公共功能的帮助程序类,主要是这种情况,它们可以执行一些重复性和常规性的工作,但是在调用之间不需要保持任何状态。


谢谢伯纳德。顺便说一句,您知道编译器“将方法绑定到类”是什么意思吗?
黑暗圣堂武士

@黑暗圣堂武士:不能说我。这是特定于特定语言的吗?
伯纳德

我对您的定义有一个小问题,“他们不依赖任何班级成员”。成员静态函数不能访问任何非静态成员,但是它们可以访问静态成员。静态成员是该类的成员。
newprint

@newprint:您是正确的,但是那不是我所说的。我说过,他们不依赖任何班级成员时。如果有必要,可以使用静态成员,但并非总是如此。
伯纳德

8

尝试提供比上述方法更简洁的解释(相当不错的解释)。

一个对象通常是代码+数据。当您只需要处理“代码”部分(没有数据/状态被维护(静态数据成员除外))时,将使用静态方法。


5

因为它们不需要实例并且可以是公共的。假设您需要一个函数来获取最大的公分母(GCD;对于分数类非常有用;是的,这只是一个简单的示例)。创建一类对象的唯一目的是可以拥有this既不需要也不用的指针gcd。因此,您可以为此使用静态方法,最好是在实际使用GCD的类上(例如,在分数类中)。

当然,如果只有静态方法,那么您将OOP做错了,应该切换到实际执行OOP或使用更适合您的范例的语言。


在您的示例中使用自由函数会更好吗?
Ela782 2014年

2
@ Ela782如果该语言具有自由功能,则可以。

好的,谢谢您的放心。我最近才学到了这种最佳实践。但是,现在我很难确定何时使用公共静态成员函数真正有用,例如使用C ++之类的语言。两者的用例是函数不依赖或不需要类的实例,然后推荐使用自由函数。也许这应该是一个新问题。
Ela782 2014年

1
@ Ela782是的,这可能是一个很好的问题。两个快速点:特别是在C ++中,静态成员对于模板元编程很有用,因为您可以将类型作为模板参数但不能将名称空间作为传递。通常,可以使用静态函数来表示该函数实际上紧密地属于某个类,而不是仅属于某个名称空间(请考虑stuff::Thing::Load(...)vs stuff::LoadThing())。

2

我将它们用作常见任务的辅助函数,示例如下:

  • 将度数转换为弧度(反之亦然);
  • 散列字符串;
  • 从枚举转换为其他枚举(在我正在从事的这个项目中,它们充当哈希表);

我对静态函数进行分组的大多数文件都有后缀Helper,这就是它们的作用,可以帮助我更快地找到所需的位置。


2

关于什么是静态方法:

静态方法既不需要类的实例,也不能隐式访问此类实例的数据(或this,self,Me等)。[ 1 ]

什么时候使用静态方法的示例:

  • 全局/辅助方法
  • 从数据模型类获取查询结果(调用SP)

仅在适当的地方使用它们。

  1. 如果发现自己在多个对象中复制相同的方法,请考虑使该方法静态化,以便遵循DRY。
  2. 如果不需要对象的实例,则使用静态方法(您不需要处理对象的实例变量)

如果您的许多数据都在对象之外,并且通过静态方法进行处理,则您的代码不是面向对象的,可能会变得难以维护。


1

静态和私有实际上是正交的:一种方法可以是静态的,也可以是私有的,或者可以是无,或两者兼有。

静态与非静态(又称“实例方法”)表明方法是在类本身上运行(静态)还是在一个特定实例上运行(非静态)。根据语言的不同,您可以通过实例调用静态方法,但是永远不能通过静态方法访问实例(这也意味着您不能从静态方法内部调用任何非静态方法,这仅仅是因为您没有this宾语)。使用静态方法来实现在概念上链接到该类但不“绑定”到一个特定实例的行为。您可能要使用静态方法的另一种情况是,当您有一个对一个类的两个实例进行操作的函数,而两个操作数都不应该享有特权状态时,例如,假设您有一个类Vector,并且您想要实现加法;您的加法可以称为a.Add(b),但Vector.Add(a, b)可能更有意义。

私有与公共是关于该方法的可见性。私有方法只能在类自己的范围内访问,而公共方法则可以在任何地方访问。最重要的用途是封装:通过仅公开其余代码与类进行通信所绝对需要的那些方法和属性,可以限制外部代码可能引入问题的点,并防止内部问题您的班级将精力投入到项目的其余部分。

因此,经验法则:

  • 将所有成员函数设为私有,但那些需要从类外部调用的成员函数除外
  • 使所有方法成为实例方法,除非即使没有该类的实例也有意义

0

对于Utility类,我在C ++和C#中都使用了静态方法,这些类没有任何实例数据,只是将有用的相关方法的集合捆绑在一起的一种方法。

int count1 = DBUtil::GetCountOfSlackerEmployees();
int count2 = DBUtil::GetCountOfEmployedSlackers();

0

假设您正在谈论C ++(您未说),并且您拥有正确的术语(即,不表示成员函数/方法):

即使私有成员函数仍必须在标头中声明,这意味着它实际上已成为类的API和ABI的一部分,即使用户实际上无法调用它也是如此。如果添加,修改或删除私有成员函数,则将强制重新编译所有相关类(标头已更改,make可能无法更好地了解),并且在库中进行此操作时,必须考虑使用它。

另一方面,文件作用域的静态函数没有公共符号,因此您可以根据需要添加,修改或删除它们,并且一个编译单元之外的任何东西都不会受到影响。



0

静态函数(该术语在不同语言中具有不同的含义)不需要在调用之间保留任何状态。如果从概念上讲它与类的功能紧密相关,则使它成为类函数(例如,在类中不是对象),否则,使它成为全局(或模块级)函数。如果不需要对象的状态,则它不属于对象。

如果您一直将状态传递给它,它实际上不是一个无状态函数,那么您只是在使用无状态语法制作一个有状态函数。在那种情况下,它可能属于调用对象,或者可能指示了一种用于更好地对齐状态和行为的重构。


0

“为什么不将所有私有成员函数替换为静态函数呢?”

...因为私有成员可以访问实例数据,同时仅允许其发生在其他成员函数内部的调用中。静态函数可以是私有的,但是除非将实例作为参数传递,否则它不能更改或引用该类的实例。


0

可笑的是,没人能给出一个好的答案。我不确定这也是。您可能应该暗示它应该尽可能少地使用。他们毕竟是程序性的,而不是面向对象的。

这里还有更多示例:

在Obj-C中,它们被称为类方法,它们通常用作分配包装器,在该包装器中,对象在返回之前被放入引用计数池中。

Obj-C的另一个示例是将新类注册到类集合中。假设您有一组类,每个类都处理一种类型的文件。当为新文件类型创建新类时,可以使用确定文件类型的类中的静态方法将其注册到集合(全局变量)中。

在C ++中,我能想到的另一种用法是轻捕获错误。您的构造函数不会失败,除非抛出异常。您可以设置一个错误实例变量,但这并不总是合适的。相反,您可以执行可能在静态包装器中失败的部分,然后分配并返回新对象,如果失败,则返回NULL。


0

假设您要计算某物的正弦值。

没有静态:

Math math = new Math()
double y = math.sin(x)

带有静态:

double y = Math.sin(x)

使sin非静态无意义。它是无状态的,仅处理输入。

静态函数不绑定到特定对象。它们是独立于对象内部状态的“一般”功能。


静态方法不是 “保证是无状态的”。虽然确实不能使用实例数据,但它们还可以访问某些状态(即静态成员,即静态方法所属的类和其他全局可见状态(例如,其他类的静态变量))。

@delnan:是的...你是对的。现在让我更正此问题。
dagnelies,2011年

没有静态:x.sin()。您的答案假设罪应该是“算术”的函数,而罪恶显然是双重的。
AjahnCharles

0

有点晚了,但我想尝试创建一个精确的定义:静态函数是不包含引用或不能引用包含类的实例属性/方法的函数。

在某些语言中,例如C#,静态类中可能包含静态字段或属性,因此说它们不用于状态是不正确的。静态函数可能会利用静态(全局)状态。

从根本上讲,它可以归结为:静态函数,就像任何静态函数一样,在有意义的意义上总是可以使用而不依赖于非静态实例时很有用。

诸如数学函数之类的辅助函数是一个经常出现的示例,但是还有其他示例。

如果您创建的类要求数据是不可变的,则创建静态实例以接收实例并传递新实例可能是有意义的,因为不能(或不应)更改实例。例如,字符串类可能具有静态函数,这些函数接收一个字符串(或2个或更多)并传回新的字符串。

另一个原因可能是有一类保留全局状态或某种数据。可能有一些静态函数可以使用该静态类中的静态属性或字段。


0

我想指出静态f()的另一种用法。

http://www.parashift.com/c++-faq/named-ctor-idiom.html

归结为这一点:static函数允许您创建“命名构造函数”,即您使用合适的且具有自文档说明的名称来命名静态函数,并且此静态函数调用其中一个构造函数(因为构造函数具有相同的名称,并且您可以使用其中很多,很难将它们区分开)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.