🌻天国にいけるC++言語入門🌻 進化し続けるオブジェクト指向プログラミング ver3.2307
ポリモーフィズムが用いられたプログラムとメンバ関数のオーバーライドが行われているだけのプログラムの違いとは関数に多態性を持たせてもプログラム内で用いられていないということなのです
ポリモーフィズムが用いられたプログラムとメンバ関数のオーバーライドが行われているだけのプログラムの違いとは関数に多態性を持たせてもプログラム内で用いられていないということなのです
ポリモーフィズムが用いられたプログラムとメンバ関数のオーバーライドが行われているだけのプログラムの違いとは関数に多態性を持たせてもプログラム内で用いられていないということなのです
ソーラー「今日は
ポリモーフィズム(多態性)が用いられたプログラムと
メンバ関数のオーバーライドが
行われているだけのプログラムの違いについて考察してみよう
のコーナーだよ(^_-)-☆」
てん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
ソーラー「😊どっかな~
このプログラムでは
オーバーライドだけが行われていて
関数のポリモーフィズム(多態性)は用いられていません
このように
関数にポリモーフィズム(多態性)を持たせても
プログラム内で
ポリモーフィズム(多態性)が用いられていないプログラムが
あるというわけなんだね」
マックス「ふっ まあそうだな
いい例だったぜぃ」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます