🌻天国にいけるC++言語入門🌻 進化し続けるオブジェクト指向プログラミング ver3.2307
ポリモーフィズムをもちいてキャラクターのステータスデータの表示される順番をいれかえてみよう 命令文全体にポリモーフィズム(多態性)を持たせてみます
プログラムのある部分全体にポリモーフィズム(多態性)を持たせてみましょう
ポリモーフィズムをもちいてキャラクターのステータスデータの表示される順番をいれかえてみよう 命令文全体にポリモーフィズム(多態性)を持たせてみます
ソーラー「今日は
ポリモーフィズムをもちいて
ゲームキャラクターのステータスデータの表示される順番をいれかえてみよう~~😊😊
ゲームによっては
ゲーム内でゲームキャラクターの並び替えをおこなうことができるものがあります
ゲームキャラクターの並び替えをおこなうと
ゲームキャラクターのステータスデータの表示される順番が
リリアーネ
HP 10
MP 5
TP 7
ポッキー
HP 20
MP 3
DP 2
シルフィ
HP 3
MP 18
EP 3
から
ポッキー
HP 20
MP 3
DP 2
シルフィ
HP 3
MP 18
EP 3
リリアーネ
HP 10
MP 5
TP 7
に変化するというわけです
今日はポリモーフィズムをもちいて
ゲームキャラクターのステータスデータの表示される順番を入れ替えてみたいと思います
まず1つの親クラスGameCharacterと
親クラスGameCharacterのメンバ変数宣言、メンバ関数宣言を
継承した
子クラスを
3つ用意します
まずは
親クラス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";
}
____________________________________
として
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";
}
____________________________________
とします。」
これらのクラスが用いられたプログラムをご覧ください
👇
#include <iostream>
#include <string>//文字列を取り扱うためにヘッダファイル <string>をインクルードしています
using namespace std;
class GameCharacter {
public:
string name;
int HP;
int MP;
virtual void statusDataDisplay();//🌞statusDataDisplay()を仮想関数に設定しました
};
void GameCharacter::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
}
class Human :public GameCharacter {
public:
int TP;//👈Human(人間)型のキャラクターだけに備わっているテクニックポイントです
void statusDataDisplay();//🌞親クラスGameCharacterのメンバ関数statusDataDisplay()のオーバーライドを行っています
};
//👇🌞🌞🌞子クラスHumanのメンバ関数statusDataDisplay() の定義です🌞🌞🌞
void Human::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "TP " << TP << "\n";
}
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";
}
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";
}
int main() {
Human Lyliane;
Lyliane.name = "リリアーネ";
Lyliane.HP = 10;
Lyliane.MP = 5;
Lyliane.TP = 7;
Dragon Pokky;
Pokky.name = "ポッキー";
Pokky.HP = 20;
Pokky.MP = 3;
Pokky.DP = 2;
Elf Sylphy;
Sylphy.name = "シルフィ";
Sylphy.HP = 3;
Sylphy.MP = 18;
Sylphy.EP = 3;
GameCharacter* a[3];
a[0] = &Lyliane;
a[1] = &Pokky;
a[2] = &Sylphy;
//👇🌞のちにゲームキャラクターのステータスデータ表示の順番を変更しますが👇この命令文たちには手を加えず変更しません
a[0]->statusDataDisplay();
a[1]->statusDataDisplay();
a[2]->statusDataDisplay();
//👆🌞のちにゲームキャラクターのステータスデータ表示の順番を変更しますが👆この命令文たちには手を加えず変更しません
return 0;
}
プログラムの実行結果
リリアーネ
HP 10
MP 5
TP 7
ポッキー
HP 20
MP 3
DP 2
シルフィ
HP 3
MP 18
EP 3
ソーラー「このプログラムの
GameCharacter* a[3];
a[0] = &Lyliane;
a[1] = &Pokky;
a[2] = &Sylphy;
に御注目下さい
aの親クラスGameCharacter*型の配列宣言
GameCharacter* a[3];
により
生成される
親クラスGameCharacter*型のポインタ変数である配列変数
a[0]
a[1]
a[2]
に
子クラスHuman型のオブジェクトLylianeのアドレス&Lyliane
子クラスDragon型のオブジェクトPokkyのアドレス&Pokky
子クラスElf型のオブジェクトSylphyのアドレス&Sylphy
を
代入することができています
親クラスGameCharacter*型のポインタ変数である配列変数
a[0]
a[1]
a[2]
に
子クラスHuman型のオブジェクトLylianeのアドレス&Lyliane
子クラスDragon型のオブジェクトPokkyのアドレス&Pokky
子クラスElf型のオブジェクトSylphyのアドレス&Sylphy
が代入された状態で
(正しい理解ではありませんが
親クラスGameCharacter*型のポインタ変数である配列変数
a[0]
a[1]
a[2]
には
親クラスGameCharacter型のオブジェクトLylianeのアドレス&Lyliane
親クラスGameCharacter型のオブジェクトPokkyのアドレス&Pokky
親クラスGameCharacter型のオブジェクトSylphyのアドレス&Sylphy
が代入されているとみなすこともできます)
a[0]->statusDataDisplay();
が実行されると
💖💖💖親クラスGameCharacter*型のポインタ変数である 💖💖💖
💖💖💖a[0]に 💖💖💖
子クラスHuman型のオブジェクトLylianeのアドレス&Lylianeが代入されているので
a[0]->statusDataDisplay();
が実行されるとき
a[0]->
は
親クラスGameCharacterのメンバ関数statusDataDisplay()
の定義にアクセスすることになりそうですが
このとき
親クラスGameCharacterのメンバ関数statusDataDisplay()は純粋仮想関数であり
子クラスHumanのメンバ関数statusDataDisplay()によって
オーバーライドされているので
a[0]->は
子クラスHumanのメンバ関数statusDataDisplay()の定義にアクセスすることになります
ですので
a[0]->statusDataDisplay();
が実行されると
子クラスHumanのメンバ関数statusDataDisplay()の定義
void Human::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "TP " << TP << "\n";
}
の
name
HP
MP
TP
に
子クラスHuman型のオブジェクトLylianeのメンバ変数
Lyliane.name
Lyliane.HP
Lyliane.MP
Lyliane.TP
が代入されたものが実行され
リリアーネ
HP 10
MP 5
TP 7
が表示されることになります
次に
a[1]->statusDataDisplay();
が実行されると
💖💖💖親クラスGameCharacter*型のポインタ変数である 💖💖💖
💖💖💖a[1]に 💖💖💖
子クラスDragon型のオブジェクトPokkyのアドレス&Pokkyが代入されているので
a[1]->statusDataDisplay();
が実行されるとき
a[1]->
は
親クラスGameCharacterのメンバ関数statusDataDisplay()
の定義にアクセスすることになりそうですが
このとき
親クラスGameCharacterのメンバ関数statusDataDisplay()は純粋仮想関数であり
子クラスDragonのメンバ関数statusDataDisplay()によって
オーバーライドされているので
a[1]->は
子クラスDragonのメンバ関数statusDataDisplay()の定義にアクセスすることになります
ですので
a[1]->statusDataDisplay();
が実行されると
子クラスDragonのメンバ関数statusDataDisplay()の定義
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";
}
の
name
HP
MP
DP
に
子クラスDragon型のオブジェクトのメンバ変数
Pokky.name
Pokky.HP
Pokky.MP
Pokky.DP
が代入されたものが実行され
ポッキー
HP 20
MP 3
DP 2
が表示されることになります
次に
a[2]->statusDataDisplay();
が実行されると
💖💖💖親クラスGameCharacter*型のポインタ変数である 💖💖💖
💖💖💖a[2]に 💖💖💖
親クラスGameCharacter型のオブジェクトSylphyのアドレス&Sylphyが代入されているので
a[2]->statusDataDisplay();
が実行されるとき
a[2]->
は
親クラスGameCharacterのメンバ関数statusDataDisplay()
の定義にアクセスすることになりそうですが
このとき
親クラスGameCharacterのメンバ関数statusDataDisplay()は純粋仮想関数であり
子クラスElfのメンバ関数statusDataDisplay()によって
オーバーライドされているので
a[2]->は
子クラスElfのメンバ関数statusDataDisplay()の定義にアクセスすることになります
ですので
a[2]->statusDataDisplay();
が実行されると
子クラスElfのメンバ関数statusDataDisplay()の定義
void Elf::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "EP " << EP << "\n";
}
の
name
HP
MP
EP
に
子クラスElf型のオブジェクトSylphyのメンバ変数
Sylphy.name
Sylphy.HP
Sylphy.MP
Sylphy.EP
が代入されたものが実行され
シルフィ
HP 3
MP 18
EP 3
が表示されることになります
つまり
親クラスのメンバ関数statusDataDisplay()がj純粋仮想関数に設定されているので
(仮想関数に設定されていても同じです)
親クラスGameCharacter*型のポインタ変数である 💖💖💖
💖💖💖a[0],a[1],a[2]に 💖💖💖
子クラスHuman型のオブジェクトLylianeのアドレス&Lyliane
子クラスDragon型のオブジェクトPokkyのアドレス&Pokky
子クラスElf型のオブジェクトSylphyのアドレス&Sylphy
を代入して
a[0]->statusDataDisplay();
a[1]->statusDataDisplay();
a[2]->statusDataDisplay();
が実行されるとき
オーバーライドが起こり
それぞれ別の子クラスの(オーバーライドしている)メンバ関数が実行されることになります
今度は
ポリモーフィズム(多態性)
を用いて
プログラムの実行結果
リリアーネ
HP 10
MP 5
TP 7
ポッキー
HP 20
MP 3
DP 2
シルフィ
HP 3
MP 18
EP 3
とゲームキャラクターのステータスデータが表示されている状態から
プログラムの実行結果
ポッキー
HP 20
MP 3
DP 2
シルフィ
HP 3
MP 18
EP 3
リリアーネ
HP 10
MP 5
TP 7
と
ゲームキャラクターのステータスデータが表示されている状態に
入れ替えてみたいと思います」
マックス「
ポリモーフィズム(多態性)
をもちいてか?
a[0]->statusDataDisplay();
a[1]->statusDataDisplay();
a[2]->statusDataDisplay();
は
すでに
ポリモーフィズム(多態性)
をそなえているんじゃないか?」
ソーラー「今のプログラムでは
ポリモーフィズム(多態性)
はもちいられていません
単にメンバ関数statusDataDisplay()のオーバーライドがおこっているだけです
確かに
a[0]
a[1]
a[2]
に代入されるアドレスを
変化させれば
a[0]->statusDataDisplay();
a[1]->statusDataDisplay();
a[2]->statusDataDisplay();
は
異なる関数を実行することになります
a[0]->statusDataDisplay();
a[1]->statusDataDisplay();
a[2]->statusDataDisplay();
は
ポリモーフィズム(多態性)を
備えていますが
今は
a[0]
a[1]
a[2]
に代入されるアドレスを
変化させたわけではないので
ポリモーフィズム(多態性)
が用いられたプログラムではないわけです」
マックス「なるほどな😊 そういうことか」
ソーラー「さて
そうだね
今度は
a[0]->statusDataDisplay();
a[1]->statusDataDisplay();
a[2]->statusDataDisplay();
の部分には
変更を加えずに
a[0]
a[1]
a[2]
に格納されているアドレスを
a[0] = &Lyliane;
a[1] = &Pokky;
a[2] = &Sylphy;
から
a[0] = &Sylphy;
a[1] = &Pokky;
a[2] =&Lyliane;
に変更することにより
プログラムの実行結果
ポッキー
HP 20
MP 3
DP 2
シルフィ
HP 3
MP 18
EP 3
リリアーネ
HP 10
MP 5
TP 7
を表示してみたいと思います
この
a[0]->statusDataDisplay();
a[1]->statusDataDisplay();
a[2]->statusDataDisplay();
の部分に
変更を加えないというところがポイントなんだよ」
そのプログラムはこちらです
👇
#include <iostream>
#include <string>//文字列を取り扱うためにヘッダファイル <string>をインクルードしています
using namespace std;
class GameCharacter {
public:
string name;
int HP;
int MP;
virtual void statusDataDisplay();//🌞ここにvirtualをつけただけです
};
void GameCharacter::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
}
class Human :public GameCharacter {
public:
int TP;//👈Human(人間)型のキャラクターだけに備わっているテクニックポイントです
void statusDataDisplay();//🌞メンバ関数statusDataDisplay()のオーバーライドを行っています
};
//👇🌞🌞🌞クラスHumanのメンバ関数statusDataDisplay() の定義です🌞🌞🌞
void Human::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "TP " << TP << "\n";
}
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";
}
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";
}
int main() {
Human Lyliane;
Lyliane.name = "リリアーネ";
Lyliane.HP = 10;
Lyliane.MP = 5;
Lyliane.TP = 7;
Dragon Pokky;
Pokky.name = "ポッキー";
Pokky.HP = 20;
Pokky.MP = 3;
Pokky.DP = 2;
Elf Sylphy;
Sylphy.name = "シルフィ";
Sylphy.HP = 3;
Sylphy.MP = 18;
Sylphy.EP = 3;
GameCharacter* a[3];
a[0] = &Lyliane;
a[1] = &Pokky;
a[2] = &Sylphy;
//👇代入されるアドレスをa[0]とa[2]で入れ替えました
a[0] = &Sylphy;
a[1] = &Pokky;
a[2] = &Lyliane;
//👇🌞ゲームキャラクターのステータスデータ表示の順番を変更しても👇この命令文たちには手を加えず変更しません
a[0]->statusDataDisplay();
a[1]->statusDataDisplay();
a[2]->statusDataDisplay();
//👆🌞ゲームキャラクターのステータスデータ表示の順番を変更しても👆この命令文たちには手を加えず変更しません
return 0;
}
プログラムの実行結果
ポッキー
HP 20
MP 3
DP 2
シルフィ
HP 3
MP 18
EP 3
リリアーネ
HP 10
MP 5
TP 7
ソーラー「ふふ やったね!😊
a[0]->statusDataDisplay();
a[1]->statusDataDisplay();
a[2]->statusDataDisplay();
の部分を変更しなくても
a[0]
a[1]
a[2]
に格納されているアドレスを
a[0] = &Lyliane;
a[1] = &Pokky;
a[2] = &Sylphy;
から
a[0] = &Sylphy;
a[1] = &Pokky;
a[2] =&Lyliane;
に変更するだけで
プログラムの実行結果
リリアーネ
HP 10
MP 5
TP 7
ポッキー
HP 20
MP 3
DP 2
シルフィ
HP 3
MP 18
EP 3
と表示されていたものを
プログラムの実行結果
ポッキー
HP 20
MP 3
DP 2
シルフィ
HP 3
MP 18
EP 3
リリアーネ
HP 10
MP 5
TP 7
に変更して表示することができました
ポリモーフィズムをもちいて
ゲームキャラクターのステータスデータの表示される順番をいれかえることができました
a[0]->statusDataDisplay();
と
a[1]->statusDataDisplay();
と
a[2]->statusDataDisplay();
は
それぞれ
ポリモーフィズム(多態性)
を備えています
また
//👇この部分全体
a[0]->statusDataDisplay();
a[1]->statusDataDisplay();
a[2]->statusDataDisplay();
//👆この部分全体
は
同じまま
別の命令を実行することができたわけです
となると
//👇この部分全体
a[0]->statusDataDisplay();
a[1]->statusDataDisplay();
a[2]->statusDataDisplay();
//👆この部分全体
も
ポリモーフィズム(多態性)を
備えているといえるんだね」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます