「静的関数」はいつ使用されますか?


24

OK、静的関数とは何かを学びましたが、プライベートメンバー関数よりもなぜ静的関数が有用なのかまだわかりません。これはちょっと新しい質問かもしれませんが、プライベートメンバー関数をすべて静的関数に置き換えるだけではどうですか?


1
それは「すべての静的関数をプライベートメンバー関数に置き換える」べきではありませんか?現在、あなたは静的メソッドのポイントが見えないので、なぜそれ以上使用しないのかを問い続けています。

5
「静的関数」とは何ですか?C ++では、少なくとも二つの意味(とC ++ 11回のドラフトを見て、最後のIがあります、彼らはのために非推奨の通知を取り除いのだstaticファイルスコープに機能を制限する。
デビッド・ソーンリー

C / C ++のファイルスコープの静的フリー関数の意味での「静的関数」、または「静的メンバー関数/メソッド」という意味ですか?それは大きな違いです!
ジャン・ヒューデック

@JanHudec:存在private memberすることを考えると、OPがOOの概念について尋ねており、ファイルスコープの静的についての手がかりがないと安全に推測できると思います。
マチューM.

@MatthieuM .:実際には、「プライベートメンバー」の存在は、まさに彼がC ++の意味での静的関数を意味すると信じるに至った理由です。ファイルスコープの静的関数とプライベートメンバー関数は、C ++で非常によく使用される2つの要素であるため、パブリック静的メンバーをプライベート非静的メンバーに置き換えることはあまり意味がありません。残念ながら、OPは応答していないようです。
1月Hudec

回答:


24

OOPを使用していると仮定すると、クラスメンバーに依存しない静的関数を使用します。それらはまだプライベートにすることができますが、このように、関連オブジェクトのインスタンスに依存しないため、最適化されます。

上記以外にも、1つのパブリック関数を実行するだけでオブジェクトのインスタンスを作成したくない場合に、静的関数が便利だと思います。これは主に、いくつかの反復的な一般的な作業を行うパブリック関数を含むヘルパークラスの場合ですが、呼び出し間で状態を維持する必要はありません。


ありがとうバーナード。ところで、コンパイラが「メソッドをクラスにバインドする」ことの意味を知っていますか?
ダークテンプラー

@ダークテンプラー:私がそう言うことはできません。これは特定の言語に固有ですか?
バーナード

「クラスのメンバーに依存していない」という定義には少し問題があります。メンバー静的関数は、非静的メンバーにはアクセスできませんが、静的メンバーにはアクセスできます。静的メンバーはクラスのメンバーです。
newprint

@newprint:あなたは正しいですが、それは私が言ったことではありません。クラスのメンバーに依存していないとき、私は言っ。必要な場合は静的メンバーを使用しても問題ありませんが、常にそうであるとは限りません。
バーナード

8

上記よりも簡単な説明を試みます(かなり良い説明)。

オブジェクトは通常、コード+データです。静的メソッドは、処理する「コード」部分しかない場合に使用されます(維持されるデータ/状態はありません(静的データメンバーを除く))。


5

インスタンスを必要とせず、パブリックにできるためです。最大公約数を得るための関数が必要だとしましょう(GCD;分数クラスに非常に役立ちます;はい、これは単なる簡単な例です)。オブジェクトのクラスを作成することに意味はありません。オブジェクトのクラスの唯一の目的は、thisで使用する必要のないポインターを使用できるようにすることですgcd。そのため、静的メソッドを使用します。理想的には、GCDを実際に使用するクラス(たとえば、分数クラス)で使用します。

静的メソッドしかない場合は、OOPが間違っているため、実際にOOPを実行するか、パラダイムにより適した言語を使用する必要があります。


あなたの例では、無料の関数を使用する方が良いと思いませんか?
Ela782

2
@ Ela782言語に無料の機能がある場合、はい。

さて、安心してくれてありがとう。最近、このベストプラクティスを学びました。ただし、現時点では、パブリックな静的メンバー関数が実際に役立つ可能性があるかどうかを確認するのに苦労しています。C++などの言語で考えてみましょう。両方のユースケースは、関数がクラスのインスタンスに依存していないか、クラスのインスタンスを必要としない場合で、その後、無料の関数が推奨されます。たぶん、これは新しい質問でしょう。
Ela782

1
@ Ela782うん、それは素晴らしい質問をすることができます。2つの簡単な点:C ++では特に、名前空間ではなくテンプレートパラメーターとして型を渡すことができるため、静的メンバーはテンプレートメタプログラミングに役立ちます。一般に、静的関数を使用して、関数が名前空間に属しているだけでなく、あるクラスに実際に密接に属していることを示すことができます(stuff::Thing::Load(...)vs と考えてくださいstuff::LoadThing())。

2

一般的なタスクのヘルパー関数としてそれらを使用します。例は次のとおりです。

  • 度をラジアンに変換(およびその逆);
  • 文字列のハッシュ。
  • 列挙型から他の何かに変換します(このプロジェクトでは、私は働いていますが、ハッシュテーブルとして機能します)。

静的関数をグループ化する私のファイルのほとんどには、接尾辞Helperがあります。つまり、それらが何をするかは、どこかに高速に移動するのに役立ちます。


2

静的メソッドとは:

静的メソッドは、クラスのインスタンスを必要とせず、そのようなインスタンスのデータ(またはthis、self、Meなど)に暗黙的にアクセスすることもできません。[ 1 ]

静的メソッドが有用な場合の例:

  • グローバル/ヘルパーメソッド
  • データモデルクラスからクエリ結果を取得する(SPを呼び出す)

適切な場合にのみ使用してください。

  1. 複数のオブジェクトで同じメソッドをコピーしている場合は、DRYをたどることができるようにメソッドを静的にすることを検討してください。
  2. オブジェクトのインスタンスが必要ない場合は静的メソッドを使用します(オブジェクトのインスタンス変数で作業を行っていません)

データの多くがオブジェクトの外部にあり、静的メソッドを介して処理されている場合、コードはオブジェクト指向ではなく、保守が困難になる可能性があります。


1

静的とプライベートは実際には直交しています。メソッドは静的、プライベート、またはなし、あるいはその両方です。

静的と非静的(別名「インスタンスメソッド」)は、メソッドがクラス自体(静的)で動作するか、特定のインスタンス(非静的)で動作するかを示します。言語によっては、インスタンスを介して静的メソッドを呼び出すことができますが、静的メソッドを介してインスタンスにアクセスすることはできません(つまり、静的メソッドの内部から非静的メソッドを呼び出すことはできません。thisオブジェクト)。静的メソッドを使用して、概念的にクラスにリンクされているが、特定のインスタンスに「バインド」されていない動作を実装します。静的メソッドを使用する別のシナリオは、クラスの2つのインスタンスで動作する関数があり、どちらのオペランドも特権ステータスに値しない場合です(たとえば、クラスがあると仮定する場合)Vector、追加を実装したい; 追加メソッドはとして呼び出すことができますa.Add(b)が、Vector.Add(a, b)おそらくもっと意味があります。

プライベートとパブリックは、メソッドの可視性に関するものです。プライベートメソッドにはクラスのスコープ内からしかアクセスできませんが、パブリックメソッドにはどこからでもアクセスできます。これの最も重要な用途はカプセル化です:クラスと通信するために残りのコードで絶対に必要なメソッドとプロパティのみを公開することにより、外部コードが問題を引き起こす可能性のあるポイントを制限し、内部の問題を防ぎますクラスがプロジェクトの残りの部分に出血するのを防ぎます。

だから、経験則:

  • クラスの外部から呼び出す必要があるものを除き、すべてのメンバー関数をプライベートにします
  • クラスのインスタンスが存在しない場合でも意味がない限り、すべてのメソッドをインスタンスメソッドにします。

0

ユーティリティクラス、インスタンスデータを持たないクラスには、C ++とC#の両方で静的メソッドを使用します。これは、有用な関連メソッドのコレクションをバンドルする1つの方法です。

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

0

あなたがC ++について話している(あなたは言わなかった)とあなたは正しい用語を持っていると仮定します(すなわち、メンバー関数/メソッドを意味しない):

プライベートメンバー関数でさえ、ヘッダーで宣言する必要があります。つまり、ユーザーが実際に呼び出すことはできなくても、実際にはクラスのAPIおよびABIの一部になります。プライベートメンバー関数を追加、変更、または削除すると、すべての依存クラスの再コンパイルが強制され(ヘッダーが変更され、makeの方がわかりにくくなります)、ライブラリで行う場合は、アプリケーションの互換性を考慮する必要がありますそれ。

一方、ファイルスコープの静的関数はパブリックシンボルを取得しないため、必要に応じて追加、変更、または削除することができ、1つのコンパイルユニット以外は影響を受けません。



0

静的関数(および異なる言語ではその用語には異なる意味があります)は、呼び出し間で保持される状態を必要としません。概念的にクラスの動作と密接に結びついている場合は、クラス関数(オブジェクトではなくクラスのように)にするか、そうでない場合はグローバル(またはモジュールレベルなど)の関数にします。オブジェクトの状態を必要としない場合、オブジェクトに属しません。

常にステートを渡しており、それが実際にはステートレス関数ではない場合、ステートレス構文でステートフル関数を作成しているだけです。その場合、おそらく呼び出し元のオブジェクトに属しているか、状態と動作をより良く調整するためのリファクタリングが示されている可能性があります。


0

「すべてのプライベートメンバー関数を代わりに静的関数に置き換えるだけではどうですか?」

...プライベートメンバーはインスタンスデータにアクセスできる一方で、他のメンバー関数内で行われた呼び出しからのみインスタンスデータにアクセスできるため 静的関数はプライベートにすることもできますが、インスタンスがパラメーターとして渡されない限り、クラスのインスタンスを変更または参照することはできません。


0

誰もまだ良い答えを出すことができなかったのは面白いです。これがどちらなのかわかりません。あなたはおそらく、それらを可能な限り少なく使用すべきであるというヒントとしてそれをとるべきです。結局のところ、OOPではなく手続き型です。

以下に例を示します。

クラスメソッドと呼ばれるObj-Cでは、オブジェクトが返される前に参照カウントプールに配置される割り当てラッパーとして一般的に使用されます。

Obj-Cの別の例は、新しいクラスをクラスコレクションに登録することです。それぞれが1種類のファイルを処理するクラスのセットがあるとします。新しいファイルタイプの新しいクラスを作成する場合、ファイルのタイプを決定するクラスの静的メソッドを使用して、コレクション(グローバル変数)に登録できます。

C ++で考えられるもう1つの用途は、エラーをソフトにキャッチすることです。例外をスローしない限り、コンストラクター関数は失敗しません。エラーインスタンス変数を設定することもできますが、それが常に適切とは限りません。代わりに、静的ラッパーで失敗する可能性のある部分を実行してから、新しいオブジェクトを割り当てて返すか、失敗するとNULLを返すことができます。


0

何かの洞を計算したいとしましょう。

静的なし:

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

静的な場合:

double y = Math.sin(x)

sin非静的にすることは意味がありません。ステートレスであり、入力を処理するだけです。

静的関数は特定のオブジェクトに関連付けられていません。これらは、オブジェクトの内部状態に依存しない「一般的な」機能です。


静的メソッド「ステートレスであることが保証されていません」。インスタンスデータを使用できないことは確かですが、状態(つまり、静的メソッドが属するクラスと、他のクラスの静的変数などの他のグローバルに表示される状態の両方の両方の静的メンバー)にもアクセスできます。

@delnan:true ...あなたは正しい。今すぐこれを修正しましょう。
-dagnelies

静的なし:x.sin()。あなたの答えは、罪は「数学」の関数であるべきだと仮定していますが、それは明らかに二重に作用しています。
アジャンチャールズ

0

ここで遅くなりましたが、正確な定義を作成したいと思います。静的関数は、含まれるクラスのインスタンスプロパティ/メソッドを参照しない、または参照できない関数です。

C#などの一部の言語では、静的クラスに静的フィールドまたは静的プロパティが存在する場合があるため、状態に使用されていないと言うのは正しくありません。静的関数は静的(グローバル)状態を利用する場合があります。

基本的に、要約すると、静的関数は、静的なものと同様に、静的でないインスタンスに依存せずに常に使用できることが理にかなっている場合に役立ちます。

数学関数のようなヘルパー関数は、よくある例ですが、他にもあります。

作成するクラスでデータが不変であることが必要な場合、インスタンスを変更して静的インスタンスを取得し、新しいインスタンスを渡す静的関数を作成することは理にかなっています。たとえば、文字列クラスには、文字列(または2つ以上)を取り込んで新しい文字列を返す静的関数があります。

もう1つの理由は、何らかのグローバルな状態またはデータを保持するクラスがあることです。その静的クラスの静的プロパティまたはフィールドで動作する静的関数が存在する場合があります。


0

静的f()の別の使用法を指摘したいと思います。

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

要するに、static関数を使用すると、「名前付きコンストラクター」を作成できます。つまり、適切な自己文書化名で静的関数に名前を付けます。この静的関数は、コンストラクターの1つを呼び出します(コンストラクターは、それらの多くは、それらを区別するのが難しくなります)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.