web-dev-qa-db-ja.com

名前空間+関数とクラスの静的メソッド

関連する関数のセットを持っている、または書くつもりだとしましょう。それらが数学に関連しているとしましょう。組織的に、私は:

  1. これらの関数を作成し、MyMath名前空間に配置し、MyMath::XYZ()を介して参照します
  2. MyMathというクラスを作成し、これらのメソッドを静的にし、同様にMyMath::XYZ()を参照します

私のソフトウェアを整理する手段として、なぜ他のものよりも一つを選ぶのでしょうか?

261
RobertL

デフォルトでは、名前空間付き関数を使用します。

クラスはオブジェクトを構築するためのものであり、名前空間を置き換えるものではありません。

オブジェクト指向コード内

Scott Meyersは、このトピックに関する彼のEffective C++ブックの「Item全体」を書きました。 Herb Sutterの記事で、この原則に関するオンラインリファレンスを見つけました。 http://www.gotw.ca/gotw/084.htm

知っておくべき重要なことは: クラスと同じ名前空間のC++関数では、そのクラスのインターフェイスに属します (関数呼び出しを解決するときに ADL がこれらの関数を検索するため)。

名前空間関数は、「friend」と宣言されていない限り、クラスの内部にはアクセスできませんが、静的メソッドにはアクセスできます。

これは、たとえば、クラスを保守するときに、クラスの内部を変更する必要がある場合、静的メソッドを含むすべてのメソッドで副作用を検索する必要があることを意味します。

拡張I

クラスのインターフェイスにコードを追加します。

C#では、アクセス権がない場合でもクラスにメソッドを追加できます。しかし、C++では、これは不可能です。

しかし、まだC++では、誰かがあなたのために書いたクラスにさえ、名前空間の関数を追加できます。

反対側から見ると、これはコードを設計する際に重要です。関数を名前空間に配置することにより、ユーザーがクラスのインターフェイスを増やしたり完成したりできるようになるためです。

拡張II

前のポイントの副作用として、複数のヘッダーで静的メソッドを宣言することはできません。すべてのメソッドは同じクラスで宣言する必要があります。

名前空間の場合、同じ名前空間の関数を複数のヘッダーで宣言できます(ほぼ標準のスワップ関数がその最良の例です)。

拡張III

名前空間の基本的なクールな点は、一部のコードでは、「using」というキーワードを使用すると、言及しないようにすることができるということです。

#include <string>
#include <vector>

// Etc.
{
   using namespace std ;
   // Now, everything from std is accessible without qualification
   string s ; // Ok
   vector v ; // Ok
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

また、「汚染」を1つのクラスに制限することもできます。

#include <string>
#include <vector>

{
   using std::string ;
   string s ; // Ok
   vector v ; // COMPILATION ERROR
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

この「パターン」は、ほぼ標準のスワップイディオムを適切に使用するために必須です。

そして、これはクラス内の静的メソッドでは不可能です。

そのため、C++名前空間には独自のセマンティクスがあります。

ただし、継承と同様の方法で名前空間を組み合わせることができるため、さらに先へ進みます。

たとえば、関数AAAの名前空間A、関数BBBの名前空間Bがある場合、名前空間Cを宣言し、キーワードus​​ingを使用してこの名前空間にAAAとBBBを入れることができます。

結論

名前空間は名前空間用です。クラスはクラス用です。

C++は、各概念が異なるように設計されており、さまざまな問題の解決策として、さまざまなケースでさまざまに使用されています。

名前空間が必要な場合はクラスを使用しないでください。

そして、あなたの場合、名前空間が必要です。

224
paercebal

私に反対する人はたくさんいますが、これが私の見方です。

クラスは、本質的に特定の種類のオブジェクトの定義です。静的メソッドは、そのオブジェクト定義に密接に結び付けられた操作を定義する必要があります。

基礎となるオブジェクトに関連付けられていない関連関数のグループを作成するだけの場合またはオブジェクトの種類の定義の場合、名前空間のみを使用します。私にとって、概念的には、これははるかに賢明です。

たとえば、あなたの場合、「MyMathとは何ですか?」 MyMathがオブジェクトの種類を定義していない場合、Iは、クラスにしないでください。

しかし、私が言ったように、私はこれについて私に反対する(激しくも)多くの人々がいることを知っています(特に、JavaおよびC#開発者)。

52
Dan Tao
  • 静的データが必要な場合は、静的メソッドを使用します。
  • それらがテンプレート関数であり、すべての関数のテンプレートパラメーターのセットを一緒に指定できるようにしたい場合は、テンプレートクラスで静的メソッドを使用します。

それ以外の場合は、名前空間付き関数を使用します。


コメントに対する回答:はい、静的メソッドと静的データは過剰に使用される傾向があります。そのため、役立つと思われるrelatedシナリオを2つだけ提供しました。 OPの特定の例(数学ルーチンのセット)で、すべてのルーチンに適用されるパラメーター(たとえば、コアデータ型と出力精度)を指定する機能が必要な場合は、次のようにします。

template<typename T, int decimalPlaces>
class MyMath
{
   // routines operate on datatype T, preserving at least decimalPlaces precision
};

// math routines for manufacturing calculations
typedef MyMath<double, 4> CAMMath;
// math routines for on-screen displays
typedef MyMath<float, 2> PreviewMath;

必要ない場合は、必ず名前空間を使用してください。

16
Shog9

名前空間にはクラスよりも多くの利点があるため、名前空間を使用する必要があります。

  • 同じヘッダーですべてを定義する必要はありません
  • すべての実装をヘッダーで公開する必要はありません
  • クラスメンバーをusingすることはできません。名前空間メンバーをusingできます
  • using classはできませんが、using namespaceはそれほど良いアイデアではありません
  • クラスを使用することは、実際に何も存在しないときに作成されるオブジェクトがあることを意味します

私の意見では、静的メンバーは非常に使いすぎです。ほとんどの場合、それらは本当に必要なものではありません。静的メンバー関数は、おそらくファイルスコープ関数としてより優れており、静的データメンバーは、より優れた、当然の評判を持つ、単なるグローバルオブジェクトです。

12
coppro

実装ファイルの匿名名前空間にプライベートデータを保持できるように、名前空間を優先します(したがって、privateメンバーとは異なり、ヘッダーにまったく表示する必要はありません)。別の利点は、usingによって、メソッドのクライアントがMyMath::の指定をオプトアウトできることです。

3
Motti

名前空間とクラスメソッドの両方に用途があります。名前空間にはファイル全体に拡散する機能がありますが、関連するすべてのコードを1つのファイルに収める必要がある場合、これは弱点となります。前述のように、クラスを使用すると、クラス内にプライベートな静的メンバーを作成することもできます。実装ファイルの匿名ネームスペースで使用できますが、クラス内に保持するよりも大きなスコープです。

0
rocd

クラスを使用するもう1つの理由-アクセス指定子を使用するオプション。その後、パブリック静的メソッドをより小さなプライベートメソッドに分割することができます。パブリックメソッドは、複数のプライベートメソッドを呼び出すことができます。

0
Milind T