ポリモーフィズムが用いられたプログラムとメンバ関数のオーバーライドが行われているだけのプログラムの違いとは関数に多態性を持たせてもプログラム内で用いられていないということなのです

ポリモーフィズムが用いられたプログラムとメンバ関数のオーバーライドが行われているだけのプログラムの違いとは関数に多態性を持たせてもプログラム内で用いられていないということなのです

ソーラー「今日は



        ポリモーフィズム(多態性)が用いられたプログラムと



メンバ関数のオーバーライドが



行われているだけのプログラムの違いについて考察してみよう


のコーナーだよ(^_-)-☆」


てんC「ソーラーさん 面白そうなコーナーですね」


ぶーにゃん「にゃお~んん😸」



マックス「今日は



    ポリモーフィズム(多態性)が用いられたプログラムと



メンバ関数のオーバーライドが行われているだけのプログラムの違い


か・・・



関数にポリモーフィズム(多態性)を持たせるためには


親クラスのメンバ関数を仮想関数もしくは純粋仮想関数に設定することと


親クラスのメンバ関数のオーバーライドが必要なんじゃないのか?」


ソーラー「そうなんです


関数にポリモーフィズム(多態性)を持たせるためには


親クラスのメンバ関数が仮想関数、もしくは純粋仮想関数に設定されていて


親クラスのメンバ関数が


子クラスのメンバ関数によってオーバーライドされている必要があります


そうすれば


関数にポリモーフィズム(多態性)を持たせることができますが


関数にポリモーフィズム(多態性)を持たせても



          プログラム内で



ポリモーフィズム(多態性)が用いられていないプログラムが


あるというわけなんだね」



マックス「なんだ そんなことか


そりゃ そうだろう


そういうプログラムもあるだろう」


ソーラー「今日は


      ポリモーフィズム(多態性)が用いられているように見えて



用いられていないプログラムについて


考察してみたいと思います


まず1つの親クラスGameCharacterと


親クラスGameCharacterのメンバ変数宣言、メンバ関数宣言を


継承した


子クラスを


3つ用意します


まずは


親クラスGameCharacterのクラス宣言と


親クラスGameCharacterのメンバ関数statusDataDisplay()


の定義を

             

👇

____________________________________


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";

}



____________________________________


として


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のメンバ変数

Pokky.name

Pokky.HP

Pokky.MP

Pokky.DP


が代入されたものが実行され



ポッキー

HP 20

MP 3

DP 2



が表示されることになります




そして


a[2]->statusDataDisplay();


が実行されると


     💖💖💖親クラスGameCharacter*型のポインタ変数である💖💖💖


           💖💖💖a[2]に💖💖💖



子クラスElf型のオブジェクト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 << "DP " << DP << "\n";

}



name

HP

MP

EP



Sylphy.name

Sylphy.HP

Sylphy.MP

Sylphy.EP


が代入されたものが実行され



シルフィ

HP 3

MP 18

DP 3



が表示されることになります



つまり


親クラスGameCharacterのメンバ関数statusDataDisplay()が純粋仮想関数に設定されているので


a[0]->statusDataDisplay();


a[1]->statusDataDisplay();


a[2]->statusDataDisplay();



が実行されるとき


オーバーライドが起こり


それぞれ親クラスのメンバ関数


statusDataDisplay()


の定義でなく


a[0]

a[1]

a[2]


に代入した子クラス型のオブジェクトのアドレス


に対応した子クラスのメンバ関数


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]->statusDataDisplay();


a[1]->statusDataDisplay();


a[2]->statusDataDisplay();


を並び替えた


a[2]->statusDataDisplay();


a[1]->statusDataDisplay();


a[0]->statusDataDisplay();


を実行したとしても



a[0]->statusDataDisplay()


a[1]->statusDataDisplay()


a[2]->statusDataDisplay()




      ポリモーフィズム(多態性)


が用いられたプログラムではないというわけです」



てんC「くすっ(#^^#)」


マックス「そんなんあたりまえじゃないのか?」


ソーラー「👇そのことを示すプログラムはこちらです」


マックス「平然と


👇そのことを示すプログラムはこちらです


行ったあ~~~~~」



👇そのことを示すプログラムはこちらです


#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();



//👇ただ並び替えた命令文を追加して記述しただけです

a[2]->statusDataDisplay();


a[1]->statusDataDisplay();


a[0]->statusDataDisplay();

//👆ただ並び替えた命令文を追加して記述しただけです


return 0;

}



プログラムの実行結果


リリアーネ

HP 10

MP 5

TP 7

ポッキー

HP 20

MP 3

DP 2

シルフィ

HP 3

MP 18

EP 3

シルフィ

HP 3

MP 18

EP 3

ポッキー

HP 20

MP 3

DP 2

リリアーネ

HP 10

MP 5

TP 7


ソーラー「😊どっかな~


このプログラムでは


オーバーライドだけが行われていて


関数のポリモーフィズム(多態性)は用いられていません


このように


関数にポリモーフィズム(多態性)を持たせても



          プログラム内で



ポリモーフィズム(多態性)が用いられていないプログラムが


あるというわけなんだね」


マックス「ふっ まあそうだな


いい例だったぜぃ」

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

作者を応援しよう!

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

応援したユーザー

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

新規登録で充実の読書を

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

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

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