★protectedメンバ★


今回も「基底クラス」となるクラスから作っていきましょう。

Monsterと言うクラスを作り、ここから「派生クラス」を作りながら色々と説明します。

少し長くなりそうですから、ファイル分割して作りましょう。

とりあえず、プロジェクトを作り↓の4つのファイルを追加してください。

  Main.h
  Main.cpp

  Monster.h
  Monster.cpp

main関数の作成


まずはmain関数を作るため、Main.cppを開きます。

<sample program cpp073-01>

/* Main.cpp */

#include "Main.h"

int main()
{
    return 0;
}

Monsterクラスの宣言


次にMonster.hを開き、Monsterクラスの宣言を作ります。

<sample program cpp073-02>

/* Monster.h */

#pragma once

class Monster {
public:

    Monster();

    void Initialize(const int hp, const int mp);

    void ShowStatus() const;

private:

    int m_hp;
    int m_mp;
};

メンバ変数としてHPとMP、メンバ関数として初期化とステータス表示を用意しました。


Monsterクラスのメンバ関数の作成


続いて関数本体を作るため、Monster.cppを開きます。

<sample program cpp073-03>

/* Monster.cpp */

#include "Monster.h"

#include <iostream>

Monster::Monster()
{

}

void Monster::Initialize(const int hp, const int mp)
{
    m_hp = hp;
    m_mp = mp;
}

void Monster::ShowStatus() const
{
    std::cout << "HP = " << m_hp << " : MP = " << m_mp << std::endl;
}

メンバ変数の初期値はコンストラクタ関数ではなく、Initialize関数で行いました。

プログラムの実行中に、何度かメンバ変数の値をリセットする必要があるのであれば、コンストラクタ関数で値を設定しないケースもあります。

コンストラクタ関数は、クラスが実体を持った時に1度しか呼び出されません。

値を初期値に戻すために、クラスの実体を破棄しなければならないのは面倒です。

別の関数にしておけば、いつでも呼び出せますのでリセットするのも簡単です。

※実際はケースバイケースです。


動作テスト


上手く作れているかどうか試すために、動作テストを行います。

Main.hを開いて、Monster.hをインクルードしましょう。

<sample program cpp073-04>

/* Main.h */

#pragma once

#include "Monster.h"

これで、Main.cppでMonsterクラスが使えるようになりました。

では、Main.cppを開いてテスト用のコードを追加しましょう。

<sample program cpp073-05>

/* Main.cpp */

#include "Main.h"

int main()
{
    Monster monster;

    monster.Initialize(100, 30);

    monster.ShowStatus();

    return 0;
}

<実行結果>

HP = 100 : MP = 30
続行するには何かキーを押してください・・・

ちゃんと実行出来ています。


さて、ここからが本番です。

このMonsterクラスを「基底クラス」として「派生クラス」を作りましょう。


派生クラスの作成


では次のファイルを追加してください。

  Dragon.h
  Dragon.cpp

Monsterクラスから派生したDragonクラスを作ります。

まずは、Dragon.hを開いて、Monsterクラスを継承したDragonクラスを作りましょう。

<sample program cpp073-06>

/* Dragon.h */

#pragma once

#include "Monster.h"

class Dragon : public Monster {

};

単純にMonsterクラスを継承しただけのクラスです。


動作テスト


きちんと継承出来ているかどうか試しましょう。

Main.hを開いて、Dragon.hをインクルードします。

<sample program cpp073-07>

/* Main.h */

#pragma once

#include "Dragon.h"

Monster.hはDragon.hでインクルードしてあるので書かなくても良いです。

次に、Main.cppを開きテスト用のコードを書きます。

<sample program cpp073-08>

/* Main.cpp */

#include "Main.h"

int main()
{
    Dragon dragon;

    dragon.Initialize(1000, 500);

    dragon.ShowStatus();

    return 0;
}

<実行結果>

HP = 1000 : MP = 500
続行するには何かキーを押してください・・・

上手くいっているようです。


派生クラス独自の関数を追加


では、ここで「派生クラス」独自の関数を追加してみます。

ドラゴンなので、ドラゴン独自の関数FireBreathを追加してみます。

FireBreath関数は「火を吐く」メッセージを表示し、MPを10減らします。

Dragon.hを開いてプロトタイプ宣言を書きましょう。

<sample program cpp073-09>

/* Dragon.h */

#pragma once

#include "Monster.h"

class Dragon : public Monster {
public:

    void FireBreath();
};

次にDragon.cppを開いて、FireBreath関数の本体を書きます。

<sample program cpp073-10>

/* Dragon.cpp */

#include "Dragon.h"

#include <iostream>

void Dragon::FireBreath()
{
    std::cout << "Fire Breath!!" << std::endl;

    m_mp -= 10;
}

出来たらビルドしてみてください。

<ビルド結果>

error C2248: 'Monster::m_mp': private メンバー (クラス 'Monster' で宣言されている) にアクセスできません。
note: 'Monster::m_mp' の宣言を確認してください
note: 'Monster' の宣言を確認してください

エラーになりました。

エラーメッセージを見ると、「m_mp」がprivateなのでアクセス出来ないと書いてあります。

DragonクラスはMonsterクラスを受け継いでいますので、メンバ変数「m_mp」も受け継いでいるはずです。

ですが、アクセス出来ないのには理由があります。

Monsterクラスのprivateは、継承先でもMonsterクラスのprivateなので、他のクラスからはアクセス出来ません。

たとえ継承された「派生クラス」からもアクセス出来ないのです。

これを解消するのが、表題の「protectedメンバ」です。


protectedメンバ


クラスのスコープは3種類あります。

private   自身のクラス内でしか使えない

public    どこからでも使える

protected 派生クラスからは使えるが、他は使えない

今回の場合、「m_hp」や「m_mp」はprotectedメンバにする事で「派生クラス」からも使えそうです。

Monster.hを開きスコープを変更してみましょう。

<sample program cpp073-11>

/* Monster.h */

#pragma once

class Monster {
public:

	Monster();

	void Initialize(const int hp, const int mp);

	void ShowStatus() const;

protected:

	int m_hp;
	int m_mp;
};

ビルドするとエラーは消えました。

Main.cppを開き、FireBreath関数を呼んでみましょう。

<sample program cpp073-12>

/* Main.cpp */

#include "Main.h"

int main()
{
    Dragon dragon;

    dragon.Initialize(1000, 500);

    dragon.ShowStatus();

    dragon.FireBreath();

    return 0;
}

<実行結果>

HP = 1000 : MP = 500
Fire Breath!!
続行するには何かキーを押してください・・・

上手くいきました!

「基底クラス」を作る時には、privateにするのかprotectedにするかよく考えてから作るようにしましょう。


次へ

戻る

目次へ