関連する関数のセットを持っている、または作成しようとしているとしましょう。それらが数学に関連しているとしましょう。組織的には、
- これらの関数を記述して
MyMath
名前空間に配置し、次のように参照しますMyMath::XYZ()
- 呼び出されるクラスを作成し、
MyMath
これらのメソッドを静的にして、同様に参照しますMyMath::XYZ()
ソフトウェアを整理する手段として、なぜどちらかを選択するのですか?
関連する関数のセットを持っている、または作成しようとしているとしましょう。それらが数学に関連しているとしましょう。組織的には、
MyMath
名前空間に配置し、次のように参照しますMyMath::XYZ()
MyMath
これらのメソッドを静的にして、同様に参照しますMyMath::XYZ()
ソフトウェアを整理する手段として、なぜどちらかを選択するのですか?
回答:
デフォルトでは、名前空間関数を使用します。
クラスはオブジェクトを構築するためのものであり、名前空間を置き換えるものではありません。
Scott Meyersは、このトピックに関する彼の「Effective C ++」本の「メンバー以外の非フレンド関数をメンバー関数よりも優先する」の項目全体を書きました。Herb Sutterの記事で、この原則に関するオンライン参照を見つけました。http://www.gotw.ca/gotw/084.htm
知っておくべき重要なことは、クラスと同じ名前空間のC ++関数では、そのクラスのインターフェイスに属します(ADLは関数呼び出しを解決するときにこれらの関数を検索するため)。
名前空間のある関数は、「friend」と宣言されていない限り、クラスの内部にはアクセスできませんが、静的メソッドにはアクセスできます。
これは、たとえば、クラスを維持するときに、クラスの内部を変更する必要がある場合は、静的なものも含め、すべてのメソッドで副作用を検索する必要があることを意味します。
クラスのインターフェースにコードを追加する。
C#では、クラスにアクセスできない場合でも、クラスにメソッドを追加できます。しかし、C ++では、これは不可能です。
ただし、C ++でも、名前空間付きの関数を追加できます。誰かが作成したクラスにも追加できます。
反対側から見ると、これはコードを設計するときに重要です。名前空間に関数を配置することにより、ユーザーにクラスのインターフェイスの増加/完成を許可するためです。
前のポイントの副作用として、複数のヘッダーで静的メソッドを宣言することは不可能です。すべてのメソッドは同じクラスで宣言する必要があります。
名前空間の場合、同じ名前空間の関数を複数のヘッダーで宣言できます(ほとんど標準のスワップ関数がその最も良い例です)。
名前空間の基本的なクールさは、一部のコードでは、キーワード "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 ++名前空間には独自のセマンティクスがあります。
しかし、継承と同様の方法で名前空間を組み合わせることができるため、さらに進んでいきます。
たとえば、名前空間Aに関数AAAがあり、名前空間Bに関数BBBがある場合、名前空間Cを宣言し、キーワードusingを使用してこの名前空間にAAAとBBBを組み込むことができます。
名前空間は名前空間用です。クラスはクラス用です。
C ++は、各概念が異なるように設計されており、さまざまな問題の解決策として、さまざまなケースでさまざまに使用されています。
名前空間が必要な場合はクラスを使用しないでください。
そしてあなたの場合、名前空間が必要です。
私に反対する人はたくさんいますが、これは私がそれを見る方法です:
クラスは本質的に特定の種類のオブジェクトの定義です。静的メソッドは、そのオブジェクト定義に密接に関連付けられている操作を定義する必要があります。
基礎となるオブジェクトまたは一種のオブジェクトの定義に関連付けられていない関連する関数のグループを作成するだけの場合は、名前空間のみを使用することになります。私にとっては、概念的には、これははるかに賢明です。
たとえば、あなたの場合、「マイマスとは何ですか?」と自問してください。MyMath
がオブジェクトの種類を定義していない場合、私はこう言います:それをクラスにしないでください。
しかし、私が言ったように、私はこれについて(激しくさえ)私に反対する多くの人々(特にJavaとC#開発者)がいることを知っています。
typedef
、それらは、テンプレートパラメータなどとしてそれらを使用する
それ以外の場合は、名前空間関数を使用します。
コメントへの応答:はい、静的メソッドと静的データは使い過ぎる傾向があります。そのため、私が役立つと思われる関連シナリオを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;
それが必要ない場合は、必ず名前空間を使用してください。
template
引数の繰り返しを回避する!
名前空間にはクラスよりも多くの利点があるため、名前空間を使用する必要があります。
using
クラスのメンバーはできません。using
名前空間のメンバーができますusing class
、using namespace
それほど良い考えではないこともあります私の意見では、静的メンバーは非常に過度に使用されています。ほとんどの場合、これらは本当に必要なものではありません。静的メンバー関数は、おそらくファイルスコープ関数として適しています。静的データメンバーは、グローバルオブジェクトであり、不当な評判があります。
inline
キーワードを使用して、ODRを満たします。
inline
であり、関数の本体を「インライン化」するものではありません。の真の(そして標準によって保証されている)目的は、inline
複数の定義を防ぐことです。C ++の「1つの定義ルール」についてお読みください。また、リンクされたSOの質問は、ODRの問題ではなくプリコンパイルされたヘッダーの問題のためにコンパイルされませんでした。
実装ファイルの匿名の名前空間にプライベートデータを含めることができるように、名前空間が望ましいです(そのため、private
メンバーとは対照的に、ヘッダーに表示する必要はありません)。別の利点はusing
、名前空間によってメソッドのクライアントが指定をオプトアウトできることですMyMath::
クラスを使用するもう1つの理由-アクセス指定子を使用するオプション。次に、パブリック静的メソッドをより小さなプライベートメソッドに分割できます。パブリックメソッドは、複数のプライベートメソッドを呼び出すことができます。
private
メソッドでさえ、プロトタイプがヘッダーでまったく公開されていない(したがって、非表示のままである)メソッドよりもアクセスしやすくなっています。匿名で名前空間が付けられた関数によって提供されるより良いカプセル化についても触れていません。
.cpp
ファイル内の名前のない名前空間内にこの情報を非表示にして、ヘッダーファイルを読み取る人に余分な情報を提供することなく、その翻訳単位に対して非公開にすることができます。事実上、私はPIMPLイディオムを擁護しようとしています。
.cpp
テンプレートを使用する場合は、ファイルに入れることはできません。
名前空間とクラスメソッドの両方に用途があります。名前空間にはファイル全体に分散する機能がありますが、関連するすべてのコードを1つのファイルに入れるように強制する必要がある場合、これは弱点です。上記のように、クラスでは、クラスにプライベート静的メンバーを作成することもできます。実装ファイルの匿名の名前空間に含めることもできますが、クラス内に置くよりも大きなスコープです。
private:
。特権アクセスが必要であると思われる多くの場合、それを除外することができます。最も「プライベート」な機能は、ヘッダーに表示されない機能です。private:
メソッドはこのメリットを享受できません。