🌻天国にいけるC++言語入門🌻 進化し続けるオブジェクト指向プログラミング ver3.2307
親クラスに子クラスに共通して設定されているメンバ関数を設定することを子クラスのメンバ関数の汎化といいます
親クラスに子クラスに共通して設定されているメンバ関数を設定することを子クラスのメンバ関数の汎化といいます
ソーラー「それでは
ある関数に
ポリモーフィズム(多態性)
を持たせる手順を
おさらいしてみよう
まずはサンプルプログラムをご覧ください
具体的には
親クラスGameCharacterのクラス宣言と
親クラスGameCharacterのメンバ関数statusDataDisplay()
の定義を
👇
____________________________________
class GameCharacter {
public:
string name;
int HP;
int MP;
virtual void statusDataDisplay();
};
void GameCharacter::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
}
____________________________________
として
1つ目の
子クラスである
Humanのクラス宣言と
子クラスHumanのメンバ関数
statusDataDisplay()
の定義を
👇
_____________________________________________________________________
class Human :public GameCharacter {
public:
int TP;//👈Human(人間)型のキャラクターだけに備わっているテクニックポイントです
void statusDataDisplay();//🌞親クラスGameCharacterのメンバ関数statusDataDisplay()のオーバーライドを行っています
void Human::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "TP " << TP << "\n";
}
____________________________________
とします。」
2つ目の
子クラスである
Dragonのクラス宣言と
子クラスDragonのメンバ関数
statusDataDisplay()
の定義を
👇
_____________________________________________________________________
class Dragon :public GameCharacter {
public:
int DP;//👈ドラゴン型のキャラクターだけに備わっているドラゴンポイントです
void statusDataDisplay();//🌞親クラスGameCharacterのメンバ関数statusDataDisplay()のオーバーライドを行っています
};
//👇🌞🌞🌞子クラスDragonのメンバ関数statusDataDisplay() の定義です🌞🌞🌞
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";
}
____________________________________
とします。」
ソーラー「
3つ目の
子クラスである
Elfのクラス宣言と
子クラスElfのメンバ関数
statusDataDisplay()
の定義を
👇
_____________________________________________________________________
class Elf:public GameCharacter {
public:
int EP;//👈エルフ型のキャラクターだけに備わっているエルフポイントです
void statusDataDisplay();
//🌞親クラスGameCharacterのメンバ関数statusDataDisplay()をオーバーライドしています
};
//👇🌞🌞🌞子クラスElfのメンバ関数statusDataDisplay() の定義です🌞🌞🌞
void Elf::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "EP " << EP << "\n";
}
____________________________________
ソーラー「具体的に
これらの
親クラスGameCharacterと
子クラス
Human
Dragon
Elf
を作製していく手順を考察してみようよ😊!
STEP 1
まず
親クラスGameCharacterとそのメンバ関数statusDataDisplay()を作製します
親クラスGameCharacterのクラス宣言と
親クラスGameCharacterのメンバ関数statusDataDisplay()
の定義を
以下のように設定します
👇
____________________________________
class GameCharacter {
public:
string name;
int HP;
int MP;
void statusDataDisplay();
};
void GameCharacter::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
}
____________________________________
ソーラー「
まずは親クラスを作製しないと始まらないね 」
STEP 2
そして
親クラスGameCharacterのメンバ変数宣言、メンバ関数宣言を
継承した
子クラス
Human
Dragon
Elf
を
用意することになりますが
子クラス
Human
Dragon
Elf
側で
親クラスGameCharacterのメンバ関数statusDataDisplay()と同じ名前の子クラス
Human
Dragon
Elf
のメンバ関数statusDataDisplay()を設定します
そのときの
子クラス
Human
Dragon
Elf
のメンバ関数statusDataDisplay()の定義は
親クラスGameCharacterのメンバ関数statusDataDisplay()の定義とは
異なるものを設定することになりますね
すなわち
親クラスGameCharacterのメンバ関数statusDataDisplay()を
子クラス
Human
Dragon
Elf
のメンバ関数statusDataDisplay()で
オーバーライドします
具体的には
子クラスである
Humanのクラス宣言と
子クラスHumanのメンバ関数
statusDataDisplay()
の定義を
👇
_____________________________________________________________________
class Human :public GameCharacter {
public:
int TP;//👈Human(人間)型のキャラクターだけに備わっているテクニックポイントです
void statusDataDisplay();//🌞親クラスGameCharacterのメンバ関数statusDataDisplay()のオーバーライドを行っています
void Human::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "TP " << TP << "\n";
}
____________________________________
とし
2つ目の
子クラスである
Dragonのクラス宣言と
子クラスDragonのメンバ関数
statusDataDisplay()
の定義を
👇
_____________________________________________________________________
class Dragon :public GameCharacter {
public:
int DP;//👈ドラゴン型のキャラクターだけに備わっているドラゴンポイントです
void statusDataDisplay();//🌞親クラスGameCharacterのメンバ関数statusDataDisplay()のオーバーライドを行っています
};
//👇🌞🌞🌞子クラスDragonのメンバ関数statusDataDisplay() の定義です🌞🌞🌞
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";
}
____________________________________
とし
3つ目の
子クラスである
Elfのクラス宣言と
子クラスElfのメンバ関数
statusDataDisplay()
の定義を
👇
_____________________________________________________________________
class Elf:public GameCharacter {
public:
int EP;//👈エルフ型のキャラクターだけに備わっているエルフポイントです
void statusDataDisplay();
//🌞親クラスGameCharacterのメンバ関数statusDataDisplay()をオーバーライドしています
};
//👇🌞🌞🌞子クラスElfのメンバ関数statusDataDisplay() の定義です🌞🌞🌞
void Elf::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "EP " << EP << "\n";
}
____________________________________
とします
STEP 3
ソーラー「親クラスGameCharacterのメンバ関数宣言
void statusDataDisplay();
に
virtual void statusDataDisplay();
や
virtual void statusDataDisplay()=0;
のように
virtual
もしくは
virtual
と
=0;
をくっつけて
親クラスGameCharacterのメンバ関数statusDataDisplay()
を
仮想関数
もしくは
純粋仮想関数に
設定します
となると
親クラスGameCharacterのクラス宣言は
以下のようになります
class GameCharacter {
public:
string name;
int HP;
int MP;
virtual void statusDataDisplay();//🌞statusDataDisplay()を仮想関数に設定します
(もしくはvirtual void statusDataDisplay()=0; //🌞statusDataDisplay()を純粋仮想関数に設定します)
};
ソーラー「ここまでで
親クラスGameCharacter
と
子クラス
Human
Dragon
Elf
の設定は完了です
次は
これらの
親クラスGameCharacter
と
子クラス
Human
Dragon
Elf
を用いて
プログラムをどのようにプログラムを実行していくかですね
STEP 4
main関数内で
親クラスGameCharacter*型のポインタ変数宣言
GameCharacter* a;
を実行し
親クラスGameCharacter*型のポインタ変数aを作製します
次に
子クラスDragon型のオブジェクト宣言
Dragon Pokky;
を実行し
子クラスDragon型のオブジェクトPokky
を作製します
次に
子クラスHuman型のオブジェクト宣言
Human Lyliane;
を実行し
子クラスHuman型のオブジェクトLyliane
を作製します
次に
子クラスElf型のオブジェクト宣言
Elf Sylphy;
を実行し
子クラスElf型のオブジェクトSylphy
を作製します
GameCharacter* a=&Pokky;
を実行することにより
親クラスGameCharacter*型のポインタ変数aに子クラスDragon型のオブジェクトPokkyのアドレス&Pokkyを代入して
a->statusDataDisplay();
を実行します
親クラスGameCharacterのメンバ関数statusDataDisplay()が
🌞仮想関数に設定されていなければ🌞
親クラスGameCharacter*型のポインタ変数aは
親クラスGameCharacterのメンバ関数statusDataDisplay()の定義にアクセスすることになります
が
この場合
親クラスGameCharacterのメンバ関数statusDataDisplay()
は
🌞仮想関数に設定されていて🌞(条件その1)
親クラスGameCharacterのメンバ関数statusDataDisplay()
は
子クラスDragonのメンバ関数statusDataDisplay()
によって
オーバーライド(条件その2)
されているので
親クラスGameCharacter*型のポインタ変数aは
子クラスDragonのメンバ関数statusDataDisplay()の定義にアクセスするようになります
ここまでが
オーバーライドの段階です
次の段階が
いよいよ
ポリモーフィズム(多態性)
の段階です
STEP 5
親クラスGameCharacter*型のポインタ変数aに
子クラスDragon型のオブジェクトPokkyのアドレス&Pokky
を代入して
a->statusDataDisplay()
を実行した場合
"子クラスDragonのメンバ関数statusDataDisplay()の定義"
が
用いられることになります
次に
親クラスGameCharacter*型のポインタ変数aに
違う子クラスHuman型のオブジェクトLylianeのアドレス&Lyliane
を代入してあげます
すると
a->statusDataDisplay()
を実行した場合
"子クラスHumanのメンバ関数statusDataDisplay()の定義"が
用いられることになります
このとき
a->statusDataDisplay()
の形は全く変更されていません
このように
a->statusDataDisplay()
の形には変更を加えなくても
親クラスGameCharacter*型のポインタ変数aに
代入される
子クラス型のオブジェクトのアドレスを変更するだけで
a->statusDataDisplay()
は
異なる命令文を実行することができます
このことを
ポリモーフィズム(多態性)
といいます
そのことを示すプログラムはこちらです
👇
#include <iostream>
#include <string>//文字列を取り扱うためにヘッダファイル <string>をインクルードしています
using namespace std;
class GameCharacter {
public:
string name;
int HP;
int MP;
virtual void statusDataDisplay() = 0;
};
class Human :public GameCharacter {
public:
int TP;//👈Human(人間)型のキャラクターだけに備わっているテクニックポイントです
void statusDataDisplay();
};
//👇🌞🌞🌞子クラスHumanのメンバ関数statusDataDisplay() の定義です🌞🌞🌞
void Human::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "TP " << TP << "\n"; //👈Human(人間)型のキャラクターだけに備わっているテクニックポイントを表示することができます
}
class Dragon :public GameCharacter {
public:
int DP;//👈ドラゴン型のキャラクターだけに備わっているドラゴンポイントです
void statusDataDisplay();
};
//👇🌞🌞🌞子クラスDragonのメンバ関数statusDataDisplay() の定義です🌞🌞🌞
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";//👈ドラゴン型のキャラクターだけに備わっているドラゴンポイントを表示することができます
}
int main() {
Human Lyliane;
Lyliane.name = "リリアーネ";
Lyliane.HP = 10;
Lyliane.MP = 8;
Lyliane.TP = 5;
Lyliane.statusDataDisplay();
Dragon Pokky;
Pokky.name = "ポッキー";
Pokky.HP = 20;
Pokky.MP = 3;
Pokky.DP = 2;
Pokky.statusDataDisplay();
GameCharacter* a = &Pokky;
a->statusDataDisplay();
a = &Lyliane;
a->statusDataDisplay();
return 0;
}
ビルド実行結果
リリアーネ
HP 10
MP 8
TP 5
ポッキー
HP 20
MP 3
DP 2
ポッキー
HP 20
MP 3
DP 2
リリアーネ
HP 10
MP 8
TP 5
マックス「
結局
親クラスGameCharacter*型のポインタ変数aと
statusDataDisplay()が用いられた
a->statusDataDisplay();
を用いて
異なる関数を実行させることができるようになった
というわけだ
仮想関数や純粋仮想関数のシステム・・・
いいシステムだな(*´▽`*)」
ソーラー「ということは・・・
子クラスDragon
子クラスHuman
子クラスElf
など
で
同じ名前のメンバ関数statusDataDisplay()が
設定されていて
親クラスGameCharacterに
statusDataDisplay()が設定されていない場合
逆に
親クラスGameCharacterに
子クラスDragon
子クラスHuman
子クラスElf
に設定されている
メンバ関数statusDataDisplay()
と
💖同じ名前の💖
仮想関数statusDataDisplay()
や
純粋仮想関数statusDataDisplay()
を設定すれば
親クラスGameCharacter*型のポインタ変数aに
子クラスDragonのアドレス&Dragon
子クラスHumanのアドレス&Human
子クラスElfのアドレス&Elf
を代入することにより
a->statusDataDisplay();
をつかって
異なる子クラスのメンバ関数の定義を実行させることができるようになるということなんです
このように
親クラスに
子クラスに共通しているメンバ関数を設定することを
子クラスのメンバ関数の汎化
といいます」
マックス「うむぅ
汎化か・・・
なんか
汎っていう字 帆に似てないか・・・?」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます