C++ 名前空間

次のような状況を考えてみましょう。1つのクラスにZaraという名前の学生が2人いる場合、それらを明確に区別するために、名前を使うだけでなく、家族の住所や両親の名前などの追加情報を使わなければなりません。

同じ状況はC++アプリケーションでも起こります。例えば、xyz()という名前の関数を書いたとします。別の利用可能なライブラリにも同じ関数xyz()が存在します。そうすると、コンパイラはどちらのxyz()関数を使用しているのか判断できません。

そのため、名前空間という概念が導入されました。これは上記の問題を解決するために特化したもので、異なるライブラリ内の同じ名前の関数、クラス、変数などを区別するための追加情報として機能します。名前空間を使用すると、コンテキストが定義されます。本質的に、名前空間はスコープを定義するものです。

コンピュータシステムの例を挙げましょう。1つのフォルダ(ディレクトリ)には複数のフォルダを含めることができ、各フォルダ内で同じファイル名を使用することはできませんが、異なるフォルダ内のファイルは同じ名前を持つことができます。

名前空間の定義

名前空間の定義にはキーワードnamespaceを使用し、その後に名前空間の名前を続けます。次のようになります:

namespace namespace_name { // コード宣言 }

名前空間付きの関数や変数を呼び出すには、前に名前空間の名前を付ける必要があります。次のようになります:

name::code; // code は変数または関数です

名前空間が変数や関数などのエンティティに対してどのようにスコープを定義するかを見てみましょう:

例

#include <iostream> using namespace std; // 1つ目の名前空間 namespace first_space{ void func(){ cout << "Inside first_space" << endl; } } // 2つ目の名前空間 namespace second_space{ void func(){ cout << "Inside second_space" << endl; } } int main () { // 1つ目の名前空間の関数を呼び出す first_space::func(); // 2つ目の名前空間の関数を呼び出す second_space::func(); return 0; }

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

Inside first_space
Inside second_space

using ディレクティブ

以下のusing namespaceディレクティブを使用すると、名前空間を使用する際に名前空間の名前を前に付ける必要がなくなります。このディレクティブは、後続のコードが指定された名前空間内の名前を使用することをコンパイラに伝えます。

例

#include <iostream> using namespace std; // 1つ目の名前空間 namespace first_space{ void func(){ cout << "Inside first_space" << endl; } } // 2つ目の名前空間 namespace second_space{ void func(){ cout << "Inside second_space" << endl; } } using namespace first_space; int main () { // 1つ目の名前空間の関数を呼び出す func(); return 0; }

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

Inside first_space

using ディレクティブは、名前空間内の特定の項目を指定するためにも使用できます。例えば、std 名前空間の cout 部分のみを使用する場合は、次のようなステートメントを使用できます:

using std::cout;

後続のコードでは、cout を使用する際に名前空間名をプレフィックスとして付ける必要がなくなります。ただし、std名前空間内の他の項目は、引き続き名前空間名をプレフィックスとして付ける必要があります。次のようになります:

例

#include <iostream> using std::cout; int main () { cout << "std::endl is used with std!" << std::endl; return 0; }

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

std::endl is used with std!

usingディレクティブによって導入された名前は、通常のスコープ規則に従います。名前はusingディレクティブの使用開始からそのスコープの終了まで可視です。このとき、スコープ外で定義された同名のエンティティは非表示になります。

非連続の名前空間

名前空間は複数の異なる部分で定義でき、したがって名前空間は複数の個別に定義された部分で構成されます。1つの名前空間の各構成部分は、複数のファイルに分散できます。

したがって、名前空間のある構成部分が別のファイルで定義されている名前を必要とする場合、その名前を宣言する必要があります。次の名前空間定義は、新しい名前空間を定義することも、既存の名前空間に新しい要素を追加することもできます:

namespace namespace_name { // コード宣言 }

ネストされた名前空間

名前空間はネスト(入れ子)にできます。ある名前空間の中に別の名前空間を定義できます。次のようになります:

namespace namespace_name1 { // コード宣言 namespace namespace_name2 { // コード宣言 } }

次の::演算子を使用して、ネストされた名前空間のメンバーにアクセスできます:

// namespace_name2 のメンバーにアクセス using namespace namespace_name1::namespace_name2; // namespace_name1 のメンバーにアクセス using namespace namespace_name1;

上記のステートメントでは、namespace_name1 を使用する場合、そのスコープ内で namespace_name2 の要素も利用可能です。次のようになります:

例

#include <iostream> using namespace std; // 1つ目の名前空間 namespace first_space{ void func(){ cout << "Inside first_space" << endl; } // 2つ目の名前空間 namespace second_space{ void func(){ cout << "Inside second_space" << endl; } } } using namespace first_space::second_space; int main () { // 2つ目の名前空間の関数を呼び出す func(); return 0; }

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

Inside second_space
その他の拡張