ネームスペース(名前空間)

ネームスペースとはグローバル変数や関数、クラスに対して所属先(有効範囲)を設定し、
名前の衝突の回避やデータ(定数やクラス)の所属先を明確にするための機能です。

■名前の衝突

グローバル変数や関数やクラスは1つのプログラム内で完全一致の名前は
認められておらずエラーになります。

問題例:
	Enemy.h
	#ifndef ENEMY_H_
	#define ENEMY_H_
		
	static const int Max = 10;	// 敵最大数

	#endif

	Shot.h

	#ifndef SHOT_H_
	#define SHOT_H_

	static const int Max = 100;	// 弾最大数

	#endif

上記のコードをコンパイルした場合、以下のエラーのような多重定義エラーが出ます。

	error C2370: 'Max' : 再定義 ; 異なるストレージ クラスです。

Cではこのエラーの回避方法は変数名を変更するしかありませんでした。

修正例:
	Enemy.h

	#ifndef ENEMY_H_
	#define ENEMY_H_

	static const int EnemyMax = 10;	// 敵最大数

	#endif

	Shot.h

	#ifndef SHOT_H_
	#define SHOT_H_

	static const int ShotMax = 100;	// 弾最大数

	#endif

C++では変数名の変更による修正ではなくnamespaceによる修正の方法があります。

■書式

●宣言
	書式例:
		namespace namescpaeの名前
		{
			// グローバルやクラスなどの定義
		}

	具体例:
		Enemy.h

		#ifndef ENEMY_H_
		#define ENEMY_H_

		namespace Enemy
		{
			static const int Max = 10;	// 敵最大数
		}

		#endif

		Shot.h

		#ifndef SHOT_H_
		#define SHOT_H_

		namespace Shot
		{
			static const int Max = 100;	// 弾最大数
		}

		#endif

●使用時(namespaceのスコープ外)
	書式例:
		namespace名::所属しているデータ

	具体例:
		#include "Enemy.h"
		#include "Shot.h"

		void main(void)
		{
			printf("敵の最大数 = %d\n", Enemy::Max);
			printf("弾の最大数 = %d\n", Shot::Max);
		}

		出力結果:
			敵の最大数 = 10
			弾の最大数 = 100

上記の具体例のようにnamespaceを使用することで
Enemy.hとShot.hのMaxがEnemyとShotに所属することになったので
コンパイラが別の変数と認識してエラーもなく実行可能となりました。
使用時の項目名で「namespaceのスコープ外」と書いているのは
namespaceのスコープ内ならば「namespace名::」は省略可能だからです。

	// Enemy.h
	namespace Enemy
	{
		static const int EnemyMax = 10;	// 敵最大数

		void PrintMax(void)
		{
			printf("敵の最大数 = %d\n", Max);
		}
	}

■階層化(入れ子)

namespaceは階層化(入れ子)にすることができます。

●書式
	書式:
		namespace namespace名その1
		{
			namespace namespace名その2
			{
				// 定数、クラス宣言
			}
		}

	具体例:
		// ファイル
		namespace File
		{
			テクスチャ
			namespace Texture
			{
				static const int Max = 100;
			}

			// サウンド
			namespace Sound
			{
				static const int Max = 20;
			}

			static const int Max = Texture::Max + Sound::Max;
		}

		void main(void)
		{
			printf("ファイル最大数 = %d\n", File::Max);
		}

●注意
	入れ子にすることで細かい分別ができるようになりますが、
	あまり細かすぎると、定数使用時のコードが長くなるので、
	やりすぎないように注意しなければいけません。

		問題コード:
			namespace Test1
			{
				namespace Test2
				{
					namespace Test3
					{
						namespace Test4
						{
							namespace Test5
							{
								static int Max = 100;
							}
						}
					}
				}
			}

			void main(void)
			{
				// 入れ子になりすぎて読みづらい
				printf("%d\n", Test1::Test2::Test3::Test4::Test5::Max);
			}

■using

usingはnamespaceをスコープ内に追加する機能を持っています。

●書式
	書式例:
		using namespace namespace名;
	
	具体例:
		// Enemy.h
		namespace Enemy
		{
			static const int Max = 10;	// 敵最大数
	
			void PrintMax(void)
			{
				printf("敵の最大数 = %d\n", Max);
			}
		}

		#include "Enemy.h"
		// namespace Enemyをスコープに追加
		using namespace Enemy;
		
		void main(void)
		{
			PrintMax();
		}

		出力結果:
			敵の最大数 = 10

	上記の具体例のようにusingを使用した場合、指定したnamespaceの所属している
	データを「namespace名::」を指定しなくても使えるようになります。

●注意点
	usingはnamespaceの所属情報を指定しなくていいので便利な一面がありますが、
	名前の衝突問題が再燃しますので、使用しすぎないように注意しなければいけません。
	また、usingはヘッダで使用してはいけません。
	usingの影響が他のcppでも出てしまい、namespaceを使用している意味がなくなります。