[ C++で開発 ]

C++名前空間

 昔C++をかじった頃は名前空間はありませんでした。Javaに手を染めてから標準C++に入ったときに、名前空間を知って、これはJavaのpackageと同じようなものだなぁと思いました。


クラスが増えてくると、クラス名等の名前定義の衝突が考えられます。古くは、定義名の先頭にプロジェクトなどの名称を接頭辞として付与する方法を取っていましたが、名前空間を使用すると効果的な管理ができるようになります。

また、UMLによる設計をしている場合、パッケージを実装するのに名前空間を使います。

名前空間の使用方法

名前空間の中に型定義を行う

名前空間を指定して関数宣言、定数定義、型定義をする場合、namespace 名前 { ... } で囲います。通常これらはヘッダファイルに記述することになります。

namespace torutk {

void clear_list();
const int MAX_LIST = 1024;
typedef unsigned char BYTE; 
class Person {
};

}

名前空間の中に配置した関数の定義をソースファイルに記述する場合も、namespace 名前 {...}で囲います。こちらはソースファイルに記述します。

namespcace torutk {

void clear_list()  // 名前空間torutk内のclear_list関数の定義
{
    // :
}

Person::Person()  // 名前空間torutk内のクラスPersonのメンバ関数定義
{
    // :
}

}

namespace 名前 { ... }による名前空間の定義は、複数個所で使用できますし、別なファイルでも使用できます。

上記の代替方法として、スコープ解決演算を使って定義する方法があります。

void torutk::clear_list()  // 名前空間torutk内のclear_list関数の定義
{
    // :
}

torutk::Person::Person()  // 名前空間torutk内のクラスPersonのメンバ関数定義
{
    // :
}

名前空間の中に定義された名前を利用

名前空間の中に定義された名前(シンボル)を使用するには、次の3つの方法があります。

  1. スコープ解決演算子を使って名前を完全記述する
  2. using宣言を使ってコンパイル単位(ファイル)で使用する名前の名前空間を指定する
  3. usingディレクティブを使って指定した名前空間をグローバルと同じに引き上げる

どの方法が望ましいかは議論があるかもしれませんが、僕はここに挙げた順に優先度を付けることがよいと考えています。

スコープ解決演算子を使って名前を完全記述

一番分かりやすいと思います。

int main()
{
    torutk::clear_list();
    torutk::Person tom("Tom Bonbadil");
    // :
}

using宣言を使用

名前の完全記述をusingで指定すると、以降名前を直接使用することができます。

using torutk::clear_list;
using torutk::Person;

int main()
{
    clear_list();
    Person tom("Tom Bonbadil");
    // :
}

usingディレクティブを使用

名前空間をusingで指定すると、以降その名前空間内で宣言・定義される名前(シンボル)はすべてスコープ解決演算子なしに直接使用できます。せっかく名前空間によって名前の衝突をなくそうとしているのに、これを使ってしまっては衝突が発生し混乱のもととなります。C++言語の入門記事や書籍を見ると、たいていこの方法を使っています。困ったものです。

using namespcae torutk;

int main()
{
    clear_list();
    Person tom("Tom Bonbadil");
    // :
}

名前空間の階層化

名前空間は階層的に(入れ子に)構成することができます。

namespcae torutk {
namespcae network {
namespcae que {

class RemoteQue {
    // :
};

}
}
}

この場合、torutk::network::que::RemoteQue のように使用します。

名前空間の参照は、名前空間トップからの絶対パス的な指定方法、相対パス的な指定方法、同一名前空間内の指定があります。

たとえば、次のような名前空間の構成になっていた場合、

  +--- network
  |      +--- que
  +--- que

名前空間networkの構成要素中にque::MyQueと指定した場合、netowrk::que::MyQueと解釈されます。

名前空間のエイリアス

C++は複雑な言語です。名前空間を別な名前空間名に置き換えることまでできます。

namespace netque = torutk::network::que;

int main()
{
    netque::RemoteQue que("localhost:1092");
    // :
}

匿名名前空間

注意点

ヘッダファイルでusingディレクティブを使わない

ヘッダファイル中にusingディレクティブを使用すると、ヘッダファイルをインクルードするソースファイルに思わぬ副作用を招きます。ヘッダファイルに記述されると利用者が制御することができなくなります。これは禁じ手と思うようにしています。