関連する関数のセットをすでに持っている、またはこれから作成するとします。これらは数学に関連する関数だとします。組織的には、次のようにすべきでしょうか。
- これらの関数を書いて自分の
MyMath
名前空間に配置し、次のように参照します。MyMath::XYZ()
- というクラスを作成し
MyMath
、これらのメソッドを静的にして同様に参照します。MyMath::XYZ()
ソフトウェアを整理する手段として、どちらか一方を選択する理由は何でしょうか?
ベストアンサー1
デフォルトでは、名前空間関数を使用します。
クラスはオブジェクトを構築するためのものであり、名前空間を置き換えるものではありません。
オブジェクト指向コードでは
Scott Meyers は、このトピックについて、Effective C++ の本で「メンバー関数よりも非メンバー非フレンド関数を優先する」という記事を書きました。この原則に関するオンラインの参考文献を Herb Sutter の記事で見つけました。http://www.gotw.ca/gotw/084.htm
知っておくべき重要なことは、C++では、クラスと同じ名前空間にあり、そのクラスをパラメータとして持つ関数は、そのクラスのインターフェースに属するということです(日常生活動作関数呼び出しを解決するときにそれらの関数を検索します)。
例えば:
- 名前空間Nがあるとします
- 名前空間Nで宣言されたクラスCがあるとします(言い換えると、その完全な名前はN::Cです)。
- 名前空間Nで宣言された関数Fがあるとします(言い換えると、その完全な名前はN::Fです)。
- 関数Fのパラメータの中にC型のパラメータがあるとする。
...そして、N::F はN::Cのパブリック インターフェースの一部になります。
名前空間関数は、「フレンド」として宣言されない限り、クラスの内部にアクセスできませんが、静的メソッドにはクラスの内部にアクセスする権限があります。
つまり、たとえば、クラスを保守するときに、クラスの内部を変更する必要がある場合は、静的メソッドも含め、すべてのメソッドで副作用を検索する必要があります。
拡張 I
クラスのインターフェースにコードを追加します。
C# では、クラスへのアクセス権がない場合でも、クラスにメソッドを追加できます。しかし、C++ ではこれは不可能です。
しかし、C++ では、誰かが作成したクラスに対しても、名前空間関数を追加できます。
逆に言えば、これはコードを設計するときに重要です。関数を名前空間に配置することで、ユーザーがクラスのインターフェースを拡張/完了することを許可することになるからです。
拡張 II
前のポイントの副作用として、複数のヘッダーで静的メソッドを宣言することはできません。すべてのメソッドは同じクラスで宣言する必要があります。
名前空間の場合、同じ名前空間の関数を複数のヘッダーで宣言できます (ほぼ標準の swap 関数がその最良の例です)。
拡張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
この「パターン」は、ほぼ標準的な swap イディオムを適切に使用するために必須です。
そして、これはクラス内の静的メソッドでは不可能です。
したがって、C++ 名前空間には独自のセマンティクスがあります。
しかし、継承と同様の方法で名前空間を組み合わせることができるため、さらに進化しています。
たとえば、A
関数 を持つ名前空間 と、関数 を持つAAA
名前空間がある場合、名前空間 を宣言し、キーワード を使ってこの名前空間にと を持ち込むことができます。B
BBB
C
AAA
BBB
using
using namespace
名前空間 D で示されているように、を使用して、名前空間の完全なコンテンツを別の名前空間内に取り込むこともできます。
namespace A
{
void AAA();
void AAA2();
}
namespace B
{
void BBB();
}
namespace C
{
using A::AAA;
using B::BBB;
}
namespace D
{
using namespace A;
using namespace B;
}
void foo()
{
C::AAA();
// C::AAA2(); // ERROR, won't compile
C::BBB();
}
void bar()
{
D::AAA();
D::AAA2();
D::BBB();
}
結論
名前空間は名前空間用です。クラスはクラス用です。
C++ は、それぞれの概念が異なるように設計されており、さまざまな問題の解決策として、さまざまなケースでさまざまな方法で使用されます。
名前空間が必要な場合はクラスを使用しないでください。
そしてあなたの場合、名前空間が必要です。