なぜC++を使うのか:ネーミングスペース


1.1.1. なぜネーミングスペース(namespace)
大規模なC言語ソフトウェアプロジェクトでは、関数とグローバル変数の名前を付けるのは容易ではありません.他のプログラマーが書いたコードと競合する可能性があるかどうかを考慮する必要があります.多くの方法は、各モジュールの関数名のセットに特定の接頭辞を付けることです.例えば、HTRequest_setInternal、HTRequest_internalなど.これにより、プログラマはこれらの関数を呼び出すたびに多くの文字を出力しなければならない.現在優れているIDE(Integrated Development Environment)を使用しても、プログラマの入力にあまり責任を負わないが、これらの文字は少し余計に見える.したがってC++はnamespaceの概念を導入し,いくつかの識別子をネーミング空間ツリー構造で組織し,コードをより優雅に見せる.また、この特性は先進的で、大規模なプロジェクトに対する役割が明らかであり、Java、C#、Pythonなどの後のプログラミング言語ではこのような特性がサポートされているが、いくつかの呼び方が異なるだけであることが明らかになった.
ネーミングスペースは、組織タイプ(class、struct、Enum)などだけでなく、グローバル変数、グローバル関数などを組織するためにも使用できます.インスタンス[2−1]に示すように、異なるモジュールの識別子は、識別子の競合を回避するために、それぞれ異なるネーミング空間に整理される.

// [2-1]

#include

namespace sock{

typedef unsigned short socket_port_t;

const char* LOOPBACK_ADDR = “127.0.0.1”;

const socket_port_t DEFUALT_HTTP_PORT = 80;

}

int main( void )

{

std::cout<<”Local HTTP addr = “< <<’:’< return 0;

}


GoogleブラウザChorme、オープンソースC++ライブラリboostなど、大規模なC++プロジェクトでネーミングスペースを使用するのに良いプロジェクトですが、ネーミングスペースを使用しない例の1つは、オープンソースC++ライブラリACE(The ADAPTIVE Communication Environment)で、各タイプの前面に接頭辞「ACE_」を付けることを選択します.識別子が長く、少し冗長に見えます.これらの識別子は、使用が容易であり、ACEのソースコードを変更しないために、インスタンス[2−2]に示すようにtypedef識別子を使用して名前を変更することができる.マクロはネーミングスペースに制限されないため、ここでは#defineを使用できません.

// [2-2]

#include

namespace ace{

typedef ACE_Mutex Mutex;

typedef ACE_Lock Lock;

}


1.1.2. コマンド空間内の識別子を参照する方法
参照識別子が現在のネーミングスペースまたはグローバルネーミングスペース内にない場合、前のセクションで新しく定義したaceコマンドスペースのMutexタイプを参照するなど、3つの方法でこの識別子を参照できます.

//

ace::Mutex mutex;

//

using ace::Mutex;

Mutex mutex;

//

using namespace ace;

Mutex mutex;


方式1は、必要に応じてドメイン演算子「::」を介して指定されたコマンド空間内の識別子のみを参照し、現在のコンパイルユニットがace内を参照する識別子が多くなく、コンパイルユニット内でこれらの識別子を使用する回数も多くない場合に適用される.
方式2はace::Mutexの識別子のみを導入し、現在のコンパイルユニット内でace::Mutexを使用する回数が多く、現在のネーミングスペース内の識別子と競合しない場合は、この方法を推奨します.
方法3は、aceネーミングスペースのすべての識別子を現在のネーミングスペースに導入し、その後、aceのすべての識別子が現在のネーミングスペースに対して表示され、識別子競合の危険性が高まる.現在のコンパイルユニットがaceコマンド空間内の識別子を多く使用し、識別子の競合の問題が発生しない場合は、この方法を使用して、文字の入力を減らすことができます.
以上の3つの方式について、第1の方式を優先することを提案して、この方式は最も識別子の衝突を生みにくくて、方式は2回目で、できるだけ第3の試験を使わないで、C++標準ライブラリに対しても第3の方式を使わないでください、少なくともSolarisシステムの中で1つのstructタイプがmap??と呼ばれているため、このタイプのヘッダファイルを参照すると、名前の競合が発生します.
また、ヘッダファイルにusing文を使用して識別子を導入しないことをお勧めします.そうしないと、これらの識別子はヘッダファイルを参照するすべてのコンパイルユニットに露出し、ネーミングスペースが機能しなくなり、ネーミング競合が発生しやすくなります.
使用するシステムAPIの場合、関数名はドメイン演算子を使用して区別することを推奨し、プログラムの可読性を向上させる.たとえば、:GetLastError()::getcwd().
なお、インスタンス[2-3]に示すように、カスタムネーミングスペースでシステムヘッダファイルを参照することは避け、識別子の混乱を回避する.

// [2-3]

namespace my_space{

#include

}


1.1.3. コマンド空間の別名
参照するネーミングスペースが長く、ネーミングスペース内のエンティティを最初の方法で参照したい場合は、ネーミングスペース別名を使用して、インスタンス[2-4]のような元のネーミングスペースに短い名前を付けることができます.

// [2-4]

namespace long_namespace{

void func( void ) { /* function body */ }

}

namespace ns = long_namespace;

int main( void )

{

ns::func();

return 0;

}


1.1.4. 匿名コマンドスペース
ネーミングスペースを宣言する名前が空の場合、ネーミングスペースは匿名ネーミングスペース(unnamed namespace)です.匿名の空間は、static定義の役割ドメインを使用して本コンパイルユニットのグローバル関数またはグローバル変数に代わるC++の新しい代替方法であり、匿名空間は名前付きネーミング空間と同様にネストすることができる.匿名ネーミングスペースにネーミングスペースの名前がないため、他のコンパイルユニット内でexternを介して変数を宣言することもできず、この変数は当然、インスタンス[2-5]のような本コンパイルユニット内でのみ表示される.

// [2-5]

#include

using namespace std;

namespace{ int i = 256; }

namespace ns{

namespace { int i = 128; }

void func(void)

{

cout<<"ns::func :" < cout<<"/t::i="<<::i< cout<<"/tns::i="< }

}

int main(void )

{

cout<<::i< cout<<"i="< cout<<"ns::i="< ns::func();

return 0;

}


匿名空間の使用はstaticの使用より少なくとも2つのメリットがあります.
1)複数の識別子関数のセットに対して1つの匿名空間を使用して宣言するだけで、staticを複数回入力する必要はありません.
2)ネストできます.これにより、異なるネーミングスペースで複数の同名の識別子を使用できます.
C++の規格では、staticの代わりに匿名ネーミング空間間でコンパイルユニット内部のグローバル変数を定義することも推奨されており、staticキーワードはここでは期限切れ(deprecated)特性とされている.