C言語の標準関数をすべて覚えている人は滅多にいないと思います。さらにC++では
標準関数やクラスが増えたため、標準で定義されている識別子をすべて覚えることは
不可能に近いです。そんな中で、関数や変数を作ろうとした場合、標準で定義されている関数名と
名前がバッティングすることも少なくありません。
現に、C++が登場した頃は、標準関数と同じ名前で、同じ引数リストを持つ関数を作って
しまい、標準関数を呼びたかったのか、自分が作った関数を呼びたかったのかわからなく
なったり、予期しないバグにぶち当たることも多々ありました。
そこで考えられたのが「名前空間」です。名前空間とは、関数名などの識別子の
名前をどこで管理するかを決める機構です。
例えば、全国に「山田太郎」さんという名前の人が10人いたとします。しかし、
「東京の山田太郎さん」と指定すれば1人かもしれません。この「東京の」にあたるのが
名前空間です。
実際は電話番号に近いかもしれません。例えば、全国に「12-3456」という電話番号が
10件あったとします。しかし、市外局番をつけて「0468-12-3456」と指定すれば、それは
必ず1件しかありませんこの「市外局番」にあたるのが名前空間です。
名前空間を作るためには以下のように宣言します。
namespace name{
// 宣言
}
例)
namespace Tokyo{
int yamada_taro;
}
|
名前空間を使用した例を示します。
#include<iostream>
using namespace std;
namespace Tokyo{
const char* Yamada = "Yamada Taro";
// TokyoのPrintName関数
void PrintName(const char* name){
cout << name << endl;
}
// TokyoのPrintName関数
void PrintName(){
cout << Yamada << endl;
// Tokyoの中ではTokyo::と指定しなくてもいい
// 同じ東京内では市外局番を省略できるのと同じ
}
}
// グローバルなPrintName
void PrintName(const char* name){
cout << name << " " << name << endl;
}
void main(){
// グローバルなPrintNameを呼ぼうとしている
PrintName(Yamada); // エラー:どこのYamadaさんだかわからない
// グローバルなPrintNameを呼ぼうとしている
PrintName(Tokyo::Yamada); // OK:TokyoのYamadaさんを指定している
// TokyoのPrintNameを呼ぼうとしている
Tokyo::PrintName("Suzuki");
}
|
上記の例のアンダーラインのように「::」演算子を用いて、どこの名前空間に所属しているかを
指定することで、目的の名前空間にアクセスすることができます。ただし、同じ名前空間内では
省略することができます。同じ市内では市外局番を省略できるのと同じ考えです。
しかし、いちいち名前空間を指定するのは面倒です。例えば東京の山田太郎さんが親戚ならば、
親戚内では「山田太郎さん」と言えば、親戚の山田太郎さんであることは「東京の」と付け加えなくても
わかります。
#include<iostream>
using namespace std;
namespace Tokyo{
const char* Yamada = "Yamada Taro";
// TokyoのPrintName関数
void PrintName(const char* name){
cout << name << endl;
}
}
// グローバルなPrintName
void PrintName(const char* name){
cout << name << " " << name << endl;
}
// これ以下は、Tokyo::と付けなくても、暗黙でTokyoを調べてくれる
using namespace Tokyo;
void main(){
// さっきはどこのYamadaさんだかわからなかったが、今回はTokyoのYamadaさんだとわかる
// しかし、PrintNameがTokyoのPrintNameだか、グローバルなPrintNameだかわからないので
// エラー
PrintName(Yamada);
// TokyoのPrintNameを呼ぼうとしている
// これはOK
Tokyo::PrintName(Tokyo::Yamada);
// グローバルなPrintNameを呼ぼうとしている
// これもOK
::PrintName("Suzuki");
}
|
上記のアンダーラインのように暗黙で名前空間を指定したい場合はこのように記述します。
暗黙で指定できる名前空間は1つではなく、2つ以上可能です。例えば上述の例では2行目で指定している
C++の標準関数用名前空間「std」と、自分で指定した(アンダーラインの部分)の「Tokyo」と2つの名前空間を
指定しています。もしこの2つの名前空間に同じ名前の関数や変数などがあった場合は「std::???」というように
指定しなければなりません。
#include<iostream>
using namespace std;
namespace Tokyo{
const char* Yamada = "Yamada Taro";
// TokyoのPrintName関数
void PrintName(const char* name){
cout << name << endl;
}
}
// グローバルなPrintName
void PrintName(const char* name){
cout << name << " " << name << endl;
}
// これ以下は、Tokyo::と付けなくても、暗黙でYamadaだけはTokyoを調べてくれる
using Tokyo::Yamada;
void main(){
// 今回は、TokyoのPrintNameは見えておらず、グローバルなPrintNameのみ見えているので
// YamadaはTokyo::を見てくれる
// OK
PrintName(Yamada);
// TokyoのPrintNameを呼ぼうとしている
// これはOK
Tokyo::PrintName(Tokyo::Yamada);
// グローバルなPrintNameを呼ぼうとしている
// YamadaはTokyo::を見てくれる
// これもOK
::PrintName(Yamada);
}
|
Yamada Taro Yamada Taro
Yamada Taro
Yamada Taro Yamada Taro
|
ある特定の変数や関数だけを暗黙で指定したい場合は、上記のアンダーラインのように
記述します。
名前空間に含めることができるのは、変数や関数だけではありません。クラス宣言自体を
名前空間に納めることもできます。
上でも述べたようにC++の標準ライブラリは「std」という名前空間に納められています。つまりcoutなど
標準で用意されているものを使う場合には、「using namespace std;」と記述するか、「std::cout」という
ように書かなくてはなりません。