名前空間
識別子の局所化
最初のほうで、名前空間について簡単に触れました
この章では、今まで曖昧にしていた名前空間について詳しく説明します
名前空間とは、プログラム内の変数や関数、クラスなどの識別子の住所です
全ての識別子がグローバルな位置にあると、それは名前の衝突の原因になります
事実、グローバルな識別子しか持たないプログラム言語では珍しくないエラーです
標準ライブラリや大規模プログラム用のモジュール群などを多用すると
それだけ識別子がグローバルな位置に増え、名前が衝突する可能性が高くなります
そのような場合に、この機能を用いるのです
名前空間の定義は namespace キーワードを使います
このキーワードの後のスコープで宣言された識別子は、指定された名前空間に局所化されます
namespace name {
...
}
name には、この名前空間の名前を指定します
名前空間の内部では、直接識別子にアクセスすることができますが
名前空間の外部からは、名前空間の名前をしていしなければ可視できません
名前空間の指定は、スコープ解決演算子を用いて指定します
name::member;
name は、名前空間を指定し member にはその名前空間内のアクセスしたい識別子を指定します
名前空間を定義することで、識別子を局所化することができます
#include<iostream>
using namespace std;
namespace Kitten {
class Kitty {};
char *str = "Kitty on your lap\n";
void sakura() { cout << "Crad Captor SAKURA\n"; }
}
int main() {
Kitten::Kitty obj;
cout << Kitten::str;
Kitten::sakura();
return 0;
}
このプログラムには、Kitten という名前空間が存在します
この名前空間にアクセスするには、スコープ解決演算子を用います
名前空間によって、Kitten 内のクラス、変数、関数などは局所化し
そのため、名前空間の外部との名前の衝突の可能性がなくなります
ただし、名前空間は必ずグローバルな位置で定義しなければならず
関数などの特定のスコープのローカルな名前空間は認められません
同一の名前空間の定義は複数に分割することも可能です
名前が同じであれば、それらは一つの名前空間とされるので
ある名前空間の定義を、複数のファイルで行うことができます
#include<iostream>
using namespace std;
namespace Kitten {
void Kitty();
char *str = "Kitty on your lap\n";
}
int main() {
Kitten::Kitty();
return 0;
}
namespace Kitten {
void Kitty() { cout << str; }
}
このプログラムでは、名前空間 Kitten が2ヶ所で作られています
これらは同じ名前空間として扱われるので、なんの問題もありません
下の Kitten は、同一の名前空間で定義されている変数 str へ直接アクセスしていますね
名前空間のネスト
名前空間は、スコープの外でなければ使えないと言いましたが例外があります
実は、名前空間はネストすることができるのです
つまり、名前空間の中に名前空間を含めることができます
階層化された名前空間へのアクセスは相対的になります
ある名前空間の中の名前空間へアクセスする場合、全ての名前空間の外であれば
名前空間のもっとも外側から順番に、目的の名前空間までスコープ演算子で指定します
名前空間の中からのアクセスであれば、当然自分の名前までは省略することができます
#include<iostream>
using namespace std;
namespace Kitten {
namespace Kitty {
char *str = "Kitty on your lap\n";
}
void print() {
cout << Kitty::str;
}
}
int main() {
Kitten::print();
cout << Kitten::Kitty::str;
return 0;
}
名前空間 Kitten の中に別の名前空間 Kitty が存在します
Kitten から Kitty へのアクセスは、Kitty を明示してメンバを選択しますが
外部からは Kitten::Kitty::member というようにアクセスしていることに注目してください
無名名前空間
名前空間には、無名の名前空間があります
これは、C言語なら static なグローバル変数に等しいものです
この、無名の名前空間を無名名前空間と呼びます
通常、グローバル変数は全ての位置からアクセスすることができます
異なるファイル間であれば、extern キーワードを使ってアクセスしました
しかし、無名名前空間にアクセスできるのは同一ファイルのみです
別ファイルから無名名前空間にアクセスすることはできず
同一ファイルからであれば、グローバル変数としてアクセスすることができます
たとえ extern を用いても、他のファイルから無名名前空間にアクセスすることはできません
#include<iostream>
using namespace std;
namespace {
char *str = "Kitty on your lap";
}
int main() {
cout << str;
return 0;
}
同一ファイル内では、グローバル変数 str として扱うことができます
ただし、無名名前空間で定義された変数 str は、他のファイルからアクセスすることができません
別ファイルからの extern char *str によるアクセスはできないのです
標準C++では、static より無名名前空間を使うことが推奨されます
namespace
namespace [identifier] { namespace-body }
宣言領域に名前をつけて、名前空間を割り当てます
identifier - 名前空間の名前を指定します。メンバを参照するのに用います
namespace-body - 名前空間の宣言領域です