C++言語解説:3-2.ネームスペース
2003-08-02 |
[C++ Index Top] [Prev] [Next] |
[概要] ネームスペースはC++の中でも比較的新しい機能です。「コードの再利用」を前提 としたC++プログラミングでは必須となる、変数名/関数名/クラス名のローカライ ズ機能について説明します。 [構成]・ネームスペースの必要性 * 大規模プログラム開発での懸念点 * グローバルネームスペースとローカルネームスペース ・ネームスペースの作成 * ネームスペースのローカルスコープ * ネームスペースのスコープ解決 * using文 * 無名ネームスペース ●ネームスペースの必要性 ◆大規模プログラム開発での懸念点 ・C++は、Cよりも大規模なコードを開発するために考案されたプログラム言語である ことは、本テキストの冒頭で説明したと思います。 ・大規模開発を実現するためにclassを用いて、概念の単位でプログラミングする手法 を今まで検討してきたわけですが、これは実際の開発現場において「必要な内容だ けが見える、中身のよくわからないCode」を多用することにつながります。 ・プログラムコード中では、それぞれのプログラマがユニークな変数名、関数名、ク ラス名を名付けますが、例えば数百人規模の開発において、名前の衝突が起きない と言い切れるでしょうか。 ・その数百人が統率の取れた組織に属するのであれば、どうにか管理可能かもしれま せん。しかしアウトソーシングを進めてサードパーティー製のライブラリを使うこ とになった場合はどうでしょうか。 ・つまり大規模開発でコードの再利用を行うのであれば、変数/関数/classの名前群 : 名前空間(namespace)管理は「大規模プログラムの開発用言語の機能」として必須 になるのです。 ◆グローバルネームスペースとローカルネームスペース ・今まで、C++のコード冒頭部に「using namespace std;」を付けてきましたが、これ が何を意味するのか考えてみたいと思います。 ・プログラムが利用するのはグローバルネームスペースです。そのプログラムコード 自身が定義した識別子(関数/変数/class等の名前)集合は、グローバルネームスペー スに配置されます。 ・それでは標準のC++に用意されている識別子は? これらは「std」と名付けられたロ ーカルネームスペースで定義されています。 ・よって using namespace std; とは文字通り「stdネームスペースをプログラムのグ ローバルネームスペースで使用する」という意味になります。 ・ネームスペースはC++の中でも比較的新しい機能であり、古いC++(最近は見たことあ りませんが)ではサポートされていません。このようなC++コンパイラで標準C++の機 能を使用するには #include <iostream.h> のように「.h」を記述し、「using namespace std;」を削除するように「1-1:学習 の準備」で説明していますが、これは全てをグローバルネームスペースで定義する という意味です。 ・ここからはコンパイラの実装により異なるのですが、恐らく #include <iostream> の場合は、stdネームスペースで定義する形になり #include <iostream.h> ではグローバルネームスペースで定義されることになるのでしょう。(*1) [List1.ネームスペース宣言の違い] ┌───────────────────────────────────┐ (1)現在のC++記述 // stdネームスペースで定義し、グローバルに取り込む #include <iostream> using namespace std; // stdネームスペースを取り込む必要あり int main() { cout << "Hello World" << endl; return 0; } (2)古いC++記述 // 全てグローバルネームスペースで定義 #include <iostream.h> int main() { cout << "Hello World" << endl; return 0; } └───────────────────────────────────┘ ┌───────────────────────────────────┐ [出力結果] Hello World └───────────────────────────────────┘ ●ネームスペースの作成 ◆ネームスペースのローカルスコープ ・今まで無意識に使ってきたように、ネームスペースを作るには「namespace」キーワ ードを使用します。 ・namespaceはネームスペースのローカルなスコープを作成します。 namesapce ネームスペース名 { // 変数,関数,クラスの宣言 } ・例えば、List2のようにSampleクラスを作成した場合、ここで定義したネームスペー スSampleNameSpace内では、特に修飾子を付けなくても変数にアクセスすることがで きます。 [List2.ローカルネームスペースの定義] ┌───────────────────────────────────┐ #include <iostream> using namespace std; namespace SampleNameSpace { int li_overflow; class Sample { int mi_count; public: Sample(int i_ini) { mi_count = i_ini; } int CountUp(int i_val) { mi_count += i_val; //li_overflowには普通にアクセスできる if (mi_count > li_overflow) return mi_count; return 0; } int Value() { return mi_count; } }; } int main() { SampleNameSpace::li_overflow = 10; //ネームスペース修飾子 SampleNameSpace::Sample objSample(5); //ネームスペース修飾子 if (objSample.CountUp(3)) { cout << "OverFlow!!! : " << objSample.Value() << endl; } else { cout << "No-OverFlow : " << objSample.Value() << endl; } if (objSample.CountUp(3)) { cout << "OverFlow!!! : " << objSample.Value() << endl; } else { cout << "No-OverFlow : " << objSample.Value() << endl; } return 0; } └───────────────────────────────────┘ ┌───────────────────────────────────┐ [出力結果] Hello World └───────────────────────────────────┘ ◆ネームスペースのスコープ解決 ・しかし、List2を見るとわかるようにSampleNameSpaceの外、ここではグローバルネ ームスペースですが、li_overflowへ初期値設定する際に SampleNameSpace::li_overflow としています。「::」はスコープ解決演算子です。以前、メンバ関数の定義にも使 用しましたね。 ・SampleNameSpace内のクラスSampleのオブジェクトobjSampleを定義する際にもスコ ープ解決演算子を必要としますが、このステートメントによりobjSampleについては ネームスペースのスコープが解決されているので、以後「::」を必要としません。 ◆ネームスペース作成の制約 ・ネームスペースは分割して作成することができます。しかし、その定義はある同一 ネームスペースの中で行わなければなりません。 ・例えば ┌───────────────────────────────────┐ namespace Sapce1 { // 宣言1 } : namespace Space1 { // 宣言2 } └───────────────────────────────────┘ のように記述した場合、これはグローバルネームスペースの中で行われているので 問題ありませんが ┌───────────────────────────────────┐ namespace Sapce1 { // 宣言1 namespace Space2 { // 宣言1b } } : namespace Space1 { // 宣言2 } namespace Space2 { // 宣言1b } └───────────────────────────────────┘ については、Space2が異なるNameSpaceで定義されているのでNGとなります。ただし Space2の定義がSpace1のスコープから外れない限り、分割は可能です。 ◆using文 ・今までローカルネームスペース内のリソースを使用するのにスコープ解決演算子を 使用していましたが、using文を使用することで指定を省略することができます。 ・以下の形式では、SampleNameSpaceの全てのリソースにアクセスできます。ネームス ペース全体が取り込まれた形です。 using namespace SampleNameSpace; ・次の形式では指定した特定メンバのみに有効です。 using SampleNameSpace::li_overflow; ・今まで使用していた using namespace std; はstdネームスペース全体を取り込んで いたわけです。もしcinやcoutのみの使用で問題無ければ using std::cout; using std::cin; と記述すれば良いことになります。 ◆無名ネームスペース ・無名ネームスペース(unnamed namespace)は、それが定義されたファイルの中でのみ 成立するネームスペースです。 namespace { // 宣言 } ・ここで宣言されたリソースは、単一ファイルの中で宣言無しに使用することができ ます。そして異なるファイルからアクセスできません。 ・同じ機能をstaticにより実現できますが、これは本来スコープの制御を目的とした ものでは無いので、C++のプログラミングでは無名ネームスペースの使用が推奨され ています。 (*1)調べた範囲では、恐らく #include <*.h> の形式ではグローバルネームスペース定義 という理解で間違い無いようです。 [Revision Table] |Revision |Date |Comments |----------|-----------|----------------------------------------------------- |1.00 |2003-08-02 |初版 [end] |
Copyright(C) 2003 Altmo
|
[C++ Index Top] [Prev] [Next] |