仮想関数の必要性はなぜでてくるのでしょうか?
ソーラー「ここで登場するのが
😊仮想関数😊
なんです
もう1 度 先程のプログラムをご覧ください
👇」
#include <iostream>
#include <string>//文字列を取り扱うためにヘッダファイル <string>をインクルードしています
using namespace std;
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";
}
class Human :public GameCharacter {
public:
int TP;//👈Human(人間)
型のキャラクターだけに備わっているテクニックポイントです
void statusDataDisplay();//🌞メンバ関数statusDataDisplay()のオーバーライドを行っています
void scanGameCharacterData(GameCharacter& a);
};
//👇🌞🌞🌞子クラスHumanのメンバ関数statusDataDisplay() の定義です🌞🌞🌞
void Human::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "TP " << TP << "\n";
}
//👇🌞🌞🌞子クラスHumanのメンバ関数scanGameCharacterData(GameCharacter& a)の定義です🌞🌞🌞
void Human::scanGameCharacterData(GameCharacter& a) {
cout << "スキャン発動!" << "\n";
cout << name << "は" << a.name << "のスキャンを開始した" << "\n";
cout << "ステータスデータ" << "\n";
a.statusDataDisplay();
}
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;
Lyliane.scanGameCharacterData(Pokky);
Lyliane.scanGameCharacterData(Sylphy);
Lyliane.scanGameCharacterData(Lyliane);
return 0;
}
プログラムの実行結果
スキャン発動!
リリアーネはポッキーのスキャンを開始した
ステータスデータ
ポッキー
HP 20
MP 3
スキャン発動!
リリアーネはシルフィのスキャンを開始した
ステータスデータ
シルフィ
HP 3
MP 18
スキャン発動!
リリアーネはリリアーネのスキャンを開始した
ステータスデータ
リリアーネ
HP 10
MP 5
ソーラー「スキャンが発動し
リリアーネが
ポッキーとシルフィ
ついでに
自分自身のステータスデータを読み取っています
このプログラムの実行結果
スキャン発動!
リリアーネはポッキーのスキャンを開始した
ステータスデータ
ポッキー
HP 20
MP 3
スキャン発動!
リリアーネはシルフィのスキャンを開始した
ステータスデータ
シルフィ
HP 3
MP 18
スキャン発動!
リリアーネはリリアーネのスキャンを開始した
ステータスデータ
リリアーネ
HP 10
MP 5
を
みても
おわかりになられますように
Human型のキャラクター リリアーネは
Human型のキャラクター特有のステータスデータ
TP 7
Dragon型のキャラクター ポッキーは
Dragon型のキャラクター特有のステータスデータ
DP 2
Elf型のキャラクター シルフィは
Elf型のキャラクター特有のステータスデータ
EP 3
をもっているのですが
それが表示されていませんね
その原因は
Lyliane.scanGameCharacterData(Lyliane);
が実行されると
クラスHumanのメンバ関数scanGameCharacterData(GameCharacter& a)の定義
👇
void Human::scanGameCharacterData(GameCharacter& a) {
cout << "スキャン発動!" << "\n";
cout << name << "は" << a.name << "のスキャンを開始した" << "\n";
cout << "ステータスデータ" << "\n";
a.statusDataDisplay();
}
の
GameCharacter& a
に
💖子クラスHuman型のオブジェクトLyliane💖
が代入されている😊
のに
あたかも
💖親クラスGameCharacter型のオブジェクトLyliane💖
が代入されているような
ことになるからなんです
すると
以下の命令文が実行されることになるのですが
👇
cout << "スキャン発動!" << "\n";
cout << Lyliane.name << "は" << Lyliane.name << "のスキャンを開始した" << "\n";
cout << "ステータスデータ" << "\n";
Lyliane.statusDataDisplay();
👆
この
Lyliane.statusDataDisplay();
が実行されるときは
親クラスGameCharacterのメンバ関数statusDataDisplay()
の定義が用いられることになります
すると
親クラスGameCharacterのメンバ関数statusDataDisplay()の定義
👇
void GameCharacter::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
}
👆
の
name
HP
MP
に
Lyliane.name
Lyliane.HP
Lyliane.MP
が代入されたものが実行されるので
リリアーネ
HP 10
MP 5
が表示されるだけで
リリアーネの
ステータスデータ
TP 7
が表示されることはありません
もし
Lyliane.scanGameCharacterData(Lyliane);
が実行されるとき
つまり
子クラスHumanのメンバ関数scanGameCharacterData(GameCharacter& a)の定義
👇
void Human::scanGameCharacterData(GameCharacter& a) {
cout << "スキャン発動!" << "\n";
cout << name << "は" << a.name << "のスキャンを開始した" << "\n";
cout << "ステータスデータ" << "\n";
a.statusDataDisplay();
}
の
親クラスGameCharacter&型の参照変数宣言
GameCharacter& a
に
💖子クラスHuman型のオブジェクトLyliane💖
😊が代入されたとき😊
そのまま
💖子クラスHuman型のオブジェクトLyliane💖
😊が代入されている😊
ことになれば
子クラスHumanのメンバ関数scanGameCharacterData(GameCharacter& a)の定義
👇
void Human::scanGameCharacterData(GameCharacter& a) {
cout << "スキャン発動!" << "\n";
cout << name << "は" << a.name << "のスキャンを開始した" << "\n";
cout << "ステータスデータ" << "\n";
a.statusDataDisplay();
}
👆
の
GameCharacter& a
に
💖子クラスHuman型のオブジェクトLyliane💖
が代入されたものが
実行されることになります
つまり
以下の命令文が実行されることになるのですが
👇
cout << "スキャン発動!" << "\n";
cout << Lyliane.name << "は" << Lyliane.name << "のスキャンを開始した" << "\n";
cout << "ステータスデータ" << "\n";
Lyliane.statusDataDisplay();
👆
この
Lyliane.statusDataDisplay();
が実行されるとき
子クラスHumanのメンバ関数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
に
Lyliane.name
Lyliane.HP
Lyliane.MP
Lyliane.TP
が代入されたものが実行されるので
リリアーネ
HP 10
MP 5
TP 7
が
コマンドプロンプト画面に表示されることになります
やったね!\(^o^)/
つまり
Lyliane.scanGameCharacterData(Pokky);
Lyliane.scanGameCharacterData(Sylphy);
Lyliane.scanGameCharacterData(Lyliane);
が実行されて
引数部分のGameCharacter& a
に
子クラスDragon型のオブジェクトPokky
子クラスElf型のオブジェクトSylphy
子クラスHuman型のオブジェクトLyliane
が代入されたとき
そのまま
子クラスDragon型のオブジェクトPokky
子クラスElf型のオブジェクトSylphy
子クラスHuman型のオブジェクトLyliane
が代入されていることになれば
親クラスGameCharacterのメンバ関数statusDataDisplay()
をオーバーライドしている
子クラスDragonのメンバ関数statusDataDisplay()
子クラスElfのメンバ関数statusDataDisplay()
子クラスHumanのメンバ関数statusDataDisplay()
をもちいて
プログラムの実行結果
スキャン発動!
リリアーネはポッキーのスキャンを開始した
ステータスデータ
ポッキー
HP 20
MP 3
DP 7//🌞ここです
スキャン発動!
リリアーネはシルフィのスキャンを開始した
ステータスデータ
シルフィ
HP 3
MP 18
EP 2//🌞ここです
スキャン発動!
リリアーネはリリアーネのスキャンを開始した
ステータスデータ
リリアーネ
HP 10
MP 5
TP 7//🌞ここです
を表示することができるというわけですが
さすがに
引数部分のGameCharacter& a
に
子クラスDragon型のオブジェクトPokky
子クラスElf型のオブジェクトSylphy
子クラスHuman型のオブジェクトLyliane
が代入されたとき
そのまま
子クラスDragon型のオブジェクトPokky
子クラスElf型のオブジェクトSylphy
子クラスHuman型のオブジェクトLyliane
が代入されているようにすることはできません
そこで
引数部分のGameCharacter& a
に
子クラスDragon型のオブジェクトPokky
子クラスElf型のオブジェクトSylphy
子クラスHuman型のオブジェクトLyliane
が代入されたとき
子クラスDragon型のオブジェクトPokky
子クラスElf型のオブジェクトSylphy
子クラスHuman型のオブジェクトLyliane
に
親クラスGameCharacterのメンバ関数statusDataDisplay()
をオーバーライドしている
子クラスDragonのメンバ関数statusDataDisplay()
子クラスElfのメンバ関数statusDataDisplay()
子クラスHumanのメンバ関数statusDataDisplay()
をもちいた
子クラスDragon型のオブジェクトPokky.(子クラスDragonのメンバ関数)statusDataDisplay()
子クラスElf型のオブジェクトSylphy.(子クラスElfのメンバ関数)statusDataDisplay()
子クラスHuman型のオブジェクトLyliane.(子クラスHumanのメンバ関数)statusDataDisplay()
が実行できるようになればよい
という考えが起こってきます」
マックス「子クラスDragon型のオブジェクトPokky
子クラスElf型のオブジェクトSylphy
子クラスHuman型のオブジェクトLyliane
に
親クラスGameCharacterのメンバ関数statusDataDisplay()
をオーバーライドしている
子クラスDragonのメンバ関数statusDataDisplay()
子クラスElfのメンバ関数statusDataDisplay()
子クラスHumanのメンバ関数statusDataDisplay()
をもちいた
子クラスDragon型のオブジェクトPokky.(子クラスDragonのメンバ関数)statusDataDisplay()
子クラスElf型のオブジェクトSylphy.(子クラスElfのメンバ関数)statusDataDisplay()
子クラスHuman型のオブジェクトLyliane.(子クラスHumanのメンバ関数)statusDataDisplay()
が実行できるようになればいい
オーバーライドしている子クラスのメンバ関数statusDataDisplay()の定義がもちいられればいいってことか?
」
ソーラー「そうなんです
親クラスGameCharacterのメンバ関数statusDataDisplay()
を仮想関数に設定すれば
引数部分のGameCharacter& a
に
子クラスDragon型のオブジェクトPokky
子クラスElf型のオブジェクトSylphy
子クラスHuman型のオブジェクトLyliane
が代入されたとき
a.statusDataDisplay()
a.statusDataDisplay()
a.statusDataDisplay()
の部分は
Pokky.statusDataDisplay()
Sylphy.statusDataDisplay()
Lyliane.statusDataDisplay()
となりますが
このとき
子クラスDragon型のオブジェクトPokky
子クラスElf型のオブジェクトSylphy
子クラスHuman型のオブジェクトLyliane
に
親クラスGameCharacterのメンバ関数statusDataDisplay()
をオーバーライドしている
子クラスDragonのメンバ関数statusDataDisplay()
子クラスElfのメンバ関数statusDataDisplay()
子クラスHumanのメンバ関数statusDataDisplay()
をもちいた
子クラスDragon型のオブジェクトPokky.(子クラスDragonのメンバ関数)statusDataDisplay()
子クラスElf型のオブジェクトSylphy.(子クラスElfのメンバ関数)statusDataDisplay()
子クラスHuman型のオブジェクトLyliane.(子クラスHumanのメンバ関数)statusDataDisplay()
が実行されることになります」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます