親クラスに子クラスに共通して設定されているメンバ関数を設定することを子クラスのメンバ関数の汎化といいます

ソーラー「それでは


ある関数に


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



を持たせる手順を


おさらいしてみよう


まずはサンプルプログラムをご覧ください



具体的には


親クラス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();


をつかって


異なる子クラスのメンバ関数の定義を実行させることができるようになるということなんです


このように



            親クラスに


   子クラスに共通しているメンバ関数を設定することを



       子クラスのメンバ関数の汎化



といいます」



マックス「うむぅ



汎化か・・・


なんか


汎っていう字 帆に似てないか・・・?」






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

作者を応援しよう!

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

応援したユーザー

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

新規登録で充実の読書を

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

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

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