イニシャライザ

■データ型のコンストラクタ

変数宣言などint型やfloat型、char型など、言語が用意しているデータ型がありますが、
実はC++ではこれらの型の変数を宣言した際にコンストラクタが実行されています。

●書式
	・書式例
		データ型 変数名(初期値);

	・具体例
		int test(10);	// testは10で初期化されている

	・例
		void main(void)
		{
			int int_test(10);
			float float_test(10.0f);

			printf("int_test = %d\n", int_test);
			printf("float_test = %f\n", float_test);
		}

		実行結果:
			int_test = 10
			float_test = 10.0

	上記の例のようにintやfloatの変数名の後ろに「(初期値)」と記述することで
	通常のデータ型でもコンストラクタが実行されて初期化が行われます。

■メンバイニシャライザ

メンバイニシャライザとはコンストラクタ時に使用する初期化方法のことで、
各メンバ変数のコンストラクタをクラスのコンストラクタが始まる直前に実行します。

●書式
	・書式
		クラス名::コンストラクタ(引数) : メンバ変数(初期値), メンバ変数(初期値)

	・具体例
		class CharaBase
		{
		public:
			CharaBase(void);
			void ShowParam(void);
		private:
			int m_Hp;
			int m_Mp;
		};

		CharaBase::CharaBase(void) : m_Hp(100), m_Mp(10)
		{
		}

		void CharaBase::ShowParam(void)
		{
			printf("Hp = %d\n", m_Hp);
			printf("Mp = %d\n", m_Mp);
		}

		void main(void)
		{
			CharaBase ch;
			ch.ShowParam();
		}

		実行結果:
			Hp = 100
			Mp = 10

●メンバイニシャライザのメリット
	・処理の効率化
		クラスのコンストラクタは以下の流れで動作します。

			①.コンストラクタが呼び出される

			②.各メンバ変数のコンストラクタが呼び出される

			③.コンストラクタが実行される

		①~③の流れで②でコンストラクタが呼びれだされて、初期化を行い、
		③で更にメンバ変数の初期化を行うならば③の処理は無駄です。
		初期化処理の無駄を省いただけですが簡単に実行できるので
		取り入れたほうがいいと思います。

	・constのメンバ変数の初期化
		const指定したメンバ変数は本来クラスのメンバ変数の宣言時に
		定義を行う必要がありますが、メンバイニシャライザを使用すると
		初期化が可能となります。

		constメンバを持ったクラスの例(エラー):
			class Test
			{
			public:
					
			private:
				const int m_TestId;
			};

			void main(void)
			{
				Test t;
			}

			constメンバを持ったクラスの例(宣言で初期化):
				class Test
				{
				public:

				private:
					const int m_TestId = 10;
				};

				void main(void)
				{
					Test t;
				}

			constメンバを持ったクラスの例(メンバイニシャライザ使用):
				class Test
				{
				public:
					Test() : m_TestId(10)
					{
					}

				private:
					const int m_TestId;
				};

				void main(void)
				{
					Test t;
				}

●メンバイニシャライザの初期化の順番
	メンバイニシャライザの初期化の順番はクラスで宣言しているメンバ変数を
	上から順番に初期化していきます。
	イニシャライザに設定している順番ではないので注意をして下さい。

	・クラス例
		class Test
		{
		public:
			Test()
			{}
		
		private:
			// m_Hp => m_Mpの順番で初期化する
			int m_Hp;
			int m_Mp;
		};

	・初期化順がイニシャライザの順番ではないという証明
		class Test
		{
		public:
			Test() : m_Mp(10), m_Hp(m_Mp * 100)
			{
			}

			void PrintParam()
			{
				printf("Hp = %d\nMp = %d\n", m_Hp, m_Mp);
			}
		private:
			int m_Hp;
			int m_Mp;
		};

		void main(void)
		{
			Test t;
			t.PrintParam();
		}

		実行結果:
			Hp = 不定(コンパイラの初期化しだい)
			Mp = 10

■基底クラスコンストラクタとイニシャライザ

イニシャライザでは基底クラスのコンストラクタの指定も可能です。

●書式:
	書式例:
		クラス名::派生クラスコンストラクタ() : 基底クラスコンストラクタ(引数)
		
	具体例:
		class ObjBase
		{
		public:
			ObjBase(int hp, int mp) : m_Hp(hp), m_Mp(mp) 
			{}

		protected:
			int m_Hp;
			int m_Mp;
		};

		class Player : public ObjBase
		{
		public:
			Player(int hp, int mp, int money) : ObjBase(hp, mp), m_Money(money)
			{
			}
			
			void PrintParam(void)
			{
				printf("Hp = %d\n", m_Hp);
				printf("Mp = %d\n", m_Mp);
				printf("Money = %d\n", m_Money);
			}
		private:
			int m_Money;
		};

		void main(void)
		{
			Player pl(100, 10, 20000);
			pl.PrintParam();
		}

		実行結果:
			Hp = 100
			Mp = 10
			Money = 20000

●基底クラスと派生クラスのイニシャライザの順番
	基底クラスと派生クラスでイニシャライザを使用した場合、
	基底クラスのイニシャライザが先に実行されます。
	※イニシャライザの順番を変えても変わりません。

	例:
		class ObjBase
		{
		public:
			ObjBase(int hp, int mp) : m_Hp(hp), m_Mp(mp) 
			{}

		protected:
			int m_Hp;
			int m_Mp;
		};

		class Player : public ObjBase
		{
		public:
			Player(int hp, int mp) : ObjBase(hp, mp), m_Money(m_Hp * m_Mp)
			{
			}
			
			void PrintParam(void)
			{
				printf("Hp = %d\n", m_Hp);
				printf("Mp = %d\n", m_Mp);
				printf("Money = %d\n", m_Money);
			}
		private:
			int m_Money;
		};

		void main(void)
		{
			Player pl(100, 10);
			pl.PrintParam();
		}

		実行結果:
			Hp = 100
			Mp = 10
			Money = 1000