仮想関数の必要性はなぜでてくるのでしょうか?

ソーラー「ここで登場するのが



         😊仮想関数😊


なんです


もう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()


が実行されることになります」




  • Twitterで共有
  • Facebookで共有
  • はてなブックマークでブックマーク

作者を応援しよう!

ハートをクリックで、簡単に応援の気持ちを伝えられます。(ログインが必要です)

応援したユーザー

応援すると応援コメントも書けます

新規登録で充実の読書を

マイページ
読書の状況から作品を自動で分類して簡単に管理できる
小説の未読話数がひと目でわかり前回の続きから読める
フォローしたユーザーの活動を追える
通知
小説の更新や作者の新作の情報を受け取れる
閲覧履歴
以前読んだ小説が一覧で見つけやすい
新規ユーザー登録無料

アカウントをお持ちの方はログイン

カクヨムで可能な読書体験をくわしく知る