C++ 名前空間 書いて覚えるための初心者自己中記事
クラス・関数・変数などの名前のことを総称して識別子(identifier)という。
複数人でプログラムを作成していて、自分が使っている識別子が誰かと被った場合などの対処として名前空間なるものがある。
前から名前空間という言葉だけは聞いたことがあって、いったい名前空間とはなんぞや・・、と思っていたけどやっと勉強することが出来て嬉しい。
とりあえず基本。
namespace Name1 { void func() { cout << "Name1::Func" << endl; } } namespace Name2{ void Func() { cout << "Name2::Func" << endl; } } void Func() { cout << "::Func" << endl; } void main() { Name1::func(); Name2::Func(); Func(); system("pause"); }
関数 Func(); が複数作られている。
そのうち二つは namespace 名前空間名 { } で囲われており、残る一つはむき出し。
namespace で囲われた関数Func(); は
とすることで呼び出せている。
よしここまでは大丈夫。
さらにむき出しの関数Func(); について。
今回むき出しの関数Func(); はグローバルな場所で実装されている。
このような状態を「グローバル名前空間に属している」という。
グローバル名前空間は名無しである。
なので、もしスコープ解決演算子を使いたい場合は
::Func();
となる。名無し。
以前変数のスコープと寿命を勉強したときにローカル変数と同名のグローバル変数を呼び出すために行った行為はこれのことだ。
そしてこの名前空間は重ねられる。
namespace My { namespace A { class Hoge { }; class Foo { }; } namespace B { class Bar { }; class Baz { }; } } void main() { My::A::Hoge myahoge; }
呼び出しも単純にスコープ解決演算子を重ねるだけ。
この重ねる・入れ子にする。とかいうのは
ネストする というらしい。
この、名前空間内の識別子を記入する際に毎回名前空間名を記述しなくてもよくなる方法が、今までとりあえず書いといてと言われていたやつで
using namespace 名前空間名;
だったのか。
using を使ったこの記述は using指令(using directive)という。
さらに特定の識別子のみにこれを適用したい場合の方法もあって、
using 名前空間名 :: 識別子;
と書くとその識別子だけはそのまま記述できる。
これを using宣言(using declaration)と言う。
また、これらのusing は関数内で使うことも可能で、それを行った場合はその関数内でのみ効果が発揮される。
さらに、名前空間名に別名を与えることが出来る。
namespace がネストしまくってる場合に使うと便利。
namespace AZ { namespace My { namespace A { class Hoge { }; class Foo { }; } namespace B { class Bar { }; class Baz { }; } } } void main() { namespace AzMyA = AZ::My::A; AzMyA::Hoge(); }
using を使う注意事項
ヘッダファイルには使わないように。
次に一つの名前空間内で関数を作るときに同じ名前空間にある関数を組み込む場合。
名前空間の指定は必要なのか?
namespace MyProgram { void Show() { cout << "こんにちわ!!" << endl; } void Run() { Show(); //名前空間の指定をしていないけど大丈夫 } } void main() { MyProgram::Run(); system("pause"); }
結果 大丈夫だった
では、同じShow();関数をグローバル名前空間にも一つ追加で。
namespace MyProgram { void Show() { cout << "こんにちわ!!" << endl; } void Run() { Show(); //名前空間の指定をしていないけど大丈夫 } } void Show() { //グローバル名前空間に同じ名前の関数を用意 } void main() { MyProgram::Run(); system("pause"); }
結果
こんにちわ!!
グローバル無視。
関数内のローカル変数とグローバル変数。と同じだな。
グローバル名前空間のほうのShow(); 関数を使いたい場合は ::Show(); でOK
さらに
void Show() { cout << "グローバル!!" << endl; } namespace MyProgram { void Run1() { Show(); } void Show() { cout << "MyProgram!!" << endl; } void Run2() { Show(); } } void main() { MyProgram::Run1(); MyProgram::Run2(); system("pause");
結果
グローバル!!
MyProgram!!
Run1(); の段階では同じ名前空間内のShow();関数をまだ見ていません。
そのためこんな結果に。
やっぱり変数の時と一緒だな。
無名名前空間
ゲシュタルト崩壊しそう・・・
↓
namespace { } //無名名前空間
テキストでは無名名前空間は内部リンケージみたいな感じと書いてある。
じゃあ外部ファイルからexternで使えるかチェック。
Add.cpp ↓
int add(1); namespace { int np(10); }
Saurce.cpp ↓
void main() { extern int add; cout << add << endl; extern int np; // ビルドエラーする cout << np << endl; // ビルドエラーする system("pause"); }
うん。使えなくなってる。
staticで内部リンケージにするのの範囲型って感じだね。
この無名名前空間はそれを置いた場所の所属になる?的な感じで書いてある。
なのでグローバルな部分に置いたらそればグローバル名前空間扱いらしい。
ただし内部リンケージ効果付き。
とりあえずここまで。