🌻天国にいけるC++言語入門🌻 進化し続けるオブジェクト指向プログラミング ver3.2307
仮想関数と純粋仮想関数のおもな違い 仮想関数では関数の定義の記述が必要で 純粋仮想関数では関数の定義の記述が必要ではありません。
純粋仮想関数が1つでもメンバ関数に設定されているクラスを 抽象クラスといいます
仮想関数と純粋仮想関数のおもな違い 仮想関数では関数の定義の記述が必要で 純粋仮想関数では関数の定義の記述が必要ではありません。
もう1度
純粋仮想関数
が用いられた
プログラムを実行してみたいと思います。
親クラスGameCharacterとそのメンバ関数statusDataDisplay()の定義を以下のように設定してみます
👇
____________________________________
class GameCharacter {
public:
string name;
int HP;
int MP;
virtual void statusDataDisplay()=0;
};
/*🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞
通常の親クラスGameCharacterのメンバ関数宣言
void statusDataDisplay();
にvirtualと=0をくっつけて
純粋仮想関数宣言
virtual void statusDataDisplay()=0;
を実行し
statusDataDisplay()を純粋仮想関数に設定しています
そして
純粋仮想関数となったクラスGameCharacterのメンバ関数
void statusDataDisplay()
の定義は記述しません。
🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞*/
____________________________________
として
親クラスGameCharacterを継承した
子クラスDragonとそのメンバ関数
statusDataDisplay()の定義を以下のように設定してみます
👇
(🌞🌞🌞親クラスGameCharacterのメンバ関数statusDataDisplay()と同じ関数名のstatusDataDisplay()
を
子クラスDragonのメンバ関数statusDataDisplay()として設定している
つまり
メンバ関数statusDataDisplay()のオーバーライドがなされているところがポイントです🌞🌞🌞)
____________________________________
class Dragon:public GameCharacter {
public:
int DP;//🌞ドラゴンポイントが設定されています
void statusDataDisplay();
};
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";
cout << " 子クラスのメンバ関数statusDataDisplay()が実行されました" << "\n";
}
//👆子クラスDragonのメンバ関数となっているstatusDataDisplay()の定義をおこなっています
//👆親クラスGameCharacterから子クラスDragonへクラスの継承を行うことにより
アクセス指定子がpublicに設定されている
親クラスGameCharacterのメンバ変数宣言
string name;
int HP;
int MP;
は
子クラスDragonのクラス宣言内に引き継がれているので
親クラスGameCharacterのメンバ変数
name
HP
MP
を
子クラスDragonのメンバ関数となっているstatusDataDisplay()内でも使用できます。
____________________________________
🌞 🌞 🌞 🌞 🌞 🌞
よく見ると
親クラスGameCharacterのメンバ関数statusDataDisplay()
のメンバ関数宣言は
virtual void statusDataDisplay()=0;
となっていて
親クラスGameCharacterのメンバ関数statusDataDisplay()
の定義は記述されていません。
親クラスGameCharacterのメンバ関数statusDataDisplay()
は
純粋仮想関数に設定されています。
そして
子クラスDragonのメンバ関数statusDataDisplay()
のメンバ関数宣言は
void statusDataDisplay();
となっています。
親クラスGameCharacterのメンバ関数statusDataDisplay()
と同じ関数名ですね
親クラスGameCharacterのメンバ関数statusDataDisplay()
は
子クラスDragonのメンバ関数statusDataDisplay()
によって
オーバーライドされています
🌞 🌞 🌞 🌞 🌞 🌞
マックス「さあ 純粋仮想関数はどのように機能するか
楽しみだな(*^▽^*)」
ソーラー「それでは😊 純粋仮想関数が用いられたプログラムを実行してみます。
そのプログラムはこちらです。」
👇
#include <iostream>
#include <string>
using namespace std;
class GameCharacter {
public:
string name;
int HP;
int MP;
virtual void statusDataDisplay() = 0;
};
//🌞親クラスGameCharacterのメンバ関数statusDataDisplay()を純粋仮想関数に設定しました
//🌞純粋仮想関数statusDataDisplay()の定義は記述しません。
class Dragon :public GameCharacter {
public:
int DP;//🌞ドラゴンポイントが設定されています
void statusDataDisplay();
};
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";
cout << "子クラスDragonのメンバ関数statusDataDisplay() が実行されました" << "\n";
}
int main() {
Dragon Pokky;
//👆PokkyのクラスDragon型のオブジェクト宣言をおこなっています
Pokky.name = "ポッキー";
Pokky.HP = 15;
Pokky.MP = 5;
Pokky.DP = 3;
/*👆子クラスDragonに親クラスGameCharacterの
メンバ変数宣言
string name;
int HP;
int MP;
が引き継がれています
そして
子クラスDragon型のオブジェクト宣言
Dragon Pokky;
により
生成される
子クラスDragon型のオブジェクトPokkyのメンバ変数
Pokky.name
Pokky.HP
Pokky.MP
にデータを代入しています*/
Pokky.statusDataDisplay();
return 0;
}
プログラムの実行結果
ポッキー
HP 15
MP 5
DP 3
子クラスDragonのメンバ関数statusDataDisplay() が実行されました
ソーラー「
このプログラムでは
Pokkyの子クラスDragon型のオブジェクト宣言
Dragon Pokky;
が実行されて
子クラスDragon型のオブジェクトPokkyのメンバ変数
Pokky.name
Pokky.HP
Pokky.MP
Pokky.DP
子クラスDragon型のオブジェクトPokkyのメンバ関数
Pokky.statusDataDisplay()
が生成されています
そして
子クラスDragon型のオブジェクトPokkyのメンバ関数
Pokky.statusDataDisplay();
が実行されているので
子クラスDragonのメンバ関数statusDataDisplay()の定義
👇
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";
cout << "子クラスDragonのメンバ関数statusDataDisplay() が実行されました" << "\n";
}
の
name
HP
MP
DP
に
子クラスDragon型のオブジェクトPokkyのメンバ変数
Pokky.name
Pokky.HP
Pokky.MP
Pokky.DP
が代入された
cout << Pokky.name << "\n";
cout << "HP " << Pokky.HP << "\n";
cout << "MP " << Pokky.MP << "\n";
cout << "DP " << Pokky.DP << "\n";
cout << "子クラスDragonのメンバ関数statusDataDisplay() が実行されました" << "\n";
が実行されているというわけです」
マックス「???
なんか めっちゃふつうのことが実行されてるんじゃないか~い
ただ単に
Pokkyの子クラスDragon型のオブジェクト宣言
Dragon Pokky;
を実行して
生成される
子クラスDragon型のオブジェクトPokkyのメンバ変数
Pokky.name
Pokky.HP
Pokky.MP
Pokky.DP
子クラスDragon型のオブジェクトPokkyのメンバ関数
Pokky.statusDataDisplay()
を用いて
Pokky.name = "ポッキー";
Pokky.HP = 15;
Pokky.MP = 5;
Pokky.DP = 3;
Pokky.statusDataDisplay();
を実行しただけじゃないか~い
単純に
子クラスDragon型のオブジェクトPokkyを作製して
Pokky.statusDataDisplay()
を実行しただけなんじゃないか?
ぜんぜん
親クラスGameCharacterの
純粋仮想関数宣言
virtual void statusDataDisplay() = 0;
は関係してこないんじゃないか
親クラスGameCharacterの
純粋仮想関数宣言
virtual void statusDataDisplay() = 0;
があってもなくても
同じビルド実行結果だろう
そもそも
純粋仮想関数
statusDataDisplay()
の定義は記述しないんだろう。
ということは
😊親クラスGameCharacter型のオブジェクト宣言😊
(親クラスですよー 親クラス!)
GameCharacter Pokky;
を実行して
親クラスGameCharacter型のオブジェクトのメンバ変数
Pokky.name
Pokky.HP
Pokky.MP
親クラスGameCharacter型のオブジェクトのメンバ関数
Pokky.statusDataDisplay()
を生成した際
Pokky.name = "ポッキー";
Pokky.HP = 15;
Pokky.MP = 5;
Pokky.statusDataDisplay();
を実行したらど~なるんだ?」
てんC「あっ 本当ですね。
純粋仮想関数
virtual void statusDataDisplay()=0:
の定義がないのに
親クラスGameCharacter型のオブジェクトPokkyのメンバ関数
Pokky.statusDataDisplay();
が実行されたら
何が実行されるのでしょうか?」
ソーラー「それは簡単な質問だね。」
マックス「なんでえ?」
ぶーにゃん「にゃ~~~んで~~~?」
ソーラー「なぜなら
クラス宣言内で
純粋仮想関数に設定されている関数があると
そのクラス型のオブジェクトを作製することはできないからなんです。
今のプログラムの例でいうと
親クラスGameCharacterのクラス宣言では
親クラスGameCharacterのメンバ関数
statusDataDisplay()が
virtual void statusDataDisplay()=0:
と
純粋仮想関数に設定にされています。
この状態では
Pokkyの親クラスGameCharacter型のオブジェクト宣言
GameCharacter Pokky;
を実行することができません。
つまり
親クラスGameCharacter型のオブジェクトPokkyを
生成することはできないんです。
試しに
GameCharacter Pokky;
を実行すると
ビルドエラーが表示されることになります。
そのプログラムはこちらとなります。」
👇
#include <iostream>
#include <string>
using namespace std;
class GameCharacter {
public:
string name;
int HP;
int MP;
virtual void statusDataDisplay() = 0;
};
//🌞子クラスGameCharacterのメンバ関数statusDataDisplay()を純粋仮想関数に設定しました
//🌞純粋仮想関数statusDataDisplay()の定義は記述しません。
class Dragon:public GameCharacter {
public:
int DP;//🌞ドラゴンポイントが設定されています
void statusDataDisplay();
};
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";
cout << "子クラスDragonのメンバ関数statusDataDisplay()が実行されました" << "\n";
}
int main() {
GameCharacter Pokky;
//👆PokkyのクラスDragon型のオブジェクト宣言をおこなっています
Pokky.name = "ポッキー";
Pokky.HP = 15;
Pokky.MP = 5;
Pokky.statusDataDisplay();
return 0;
}
ビルド実行結果
エラー (アクティブ) E0322 抽象クラス型 "GameCharacter" のオブジェクトは使用できません:
エラー C2259 'GameCharacter': 抽象クラスをインスタンス化できません。
マックス「親クラスGameCharacterのメンバ関数が純粋仮想関数に設定されていると
Pokkyの親クラスGameCharacter型のオブジェクト宣言
GameCharacter Pokky;
を実行できず
親クラスGameCharacter型のオブジェクトPokky自体を
生成することができないのか」
ソーラー「
親クラスGameCharacter型のオブジェクトPokky自体を
生成することができないので
もちろん
Pokky.statusDataDisplay();
を実行することはできないというわけです。」
てんC「そのような仕組みになっているのですか(´▽`*)」
ぶーにゃん「にゃ~~~ん😸」
マックス「結局
純粋仮想関数の設定
virtual void statusDataDisplay()=0;
は
どのようにこのプログラムの中で機能しているんだ??」
てんC「このプログラムでは
親クラスGameCharacterから子クラスDragonへ
クラスの継承がおこなわれています。
親クラスGameCharacterの
メンバ変数宣言
public:
string name;
int HP;
int MP;
親クラスGameCharacterのメンバ関数宣言
virtual void statusDataDisplay()=0;
が
子クラスDragonのクラス宣言内に
引き継がれています
このとき
親クラスGameCharacterのメンバ関数statusDataDisplay()
と
子クラスDragonのメンバ関数statusDataDisplay()
は名前がいっしょですね
親クラスGameCharacterのメンバ関数statusDataDisplay()
と
子クラスDragonのメンバ関数statusDataDisplay()
は名前が
一緒だと
メンバ関数statusDataDisplay()のオーバーライドが設定されることになります
となると
Pokkyの子クラスDragon型のオブジェクト宣言
Dragon Pokky;
により
子クラスDragon型のオブジェクトPokkyのメンバ変数
Pokky.name
Pokky.HP
Pokky.MP
Pokky.DP
と
子クラスDragon型のオブジェクトPokkyのメンバ関数
Pokky.statusDataDisplay()
が生成されることになりますが
このPokky.statusDataDisplay();
の実行においては
親クラスGameCharacterのメンバ関数
statusdatadisplay()
の定義がもちいられるのでしょうか?
それとも
子クラスDragonのメンバ関数
statusdatadisplay()
の定義がもちいられるのでしょうか?」
ソーラー「親クラスGameCharacterのメンバ関数
statusdatadisplay()
と
子クラスDragonのメンバ関数
statusdatadisplay()
は
名前が一緒の関数だね。
だから
🌞子クラスDragon型のオブジェクトPokkyのメンバ関数🌞
(子クラスがポイントです)
Pokky.statusDataDisplay();
が実行されると
オーバーライドの働きにより
子クラスDragonのメンバ関数
statusDataDisplay()
の定義が用いられることになります
すると
子クラスDragonのメンバ変数
Pokky.name
Pokky.HP
Pokky.MP
Pokky.DP
が
子クラスDragonのメンバ関数statusDataDisplay()の定義
👇
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";
cout << "子クラスDragonのメンバ関数statusDataDisplay() が実行されました" << "\n";
}
👆
の
name
HP
MP
DP
に代入されたものが実行されることになります
このように
親クラスGameCharacterのメンバ関数
statusDataDisplay()
が
子クラスDragonのメンバ関数
statusDataDisplay()
によって
オーバーライドされていると
Pokkyの子クラスDragon型のオブジェクト宣言
Dragon Pokky;
を実行して
子クラスDragon型のオブジェクトPokkyを作製して
子クラスDragon型のオブジェクトPokkyのメンバ関数statusDataDisplay()
Pokky.statusDataDisplay();
が実行されるとき
親クラスGameCharacterのメンバ関数statusDataDisplay()でなく
子クラスDragonのメンバ関数statusDataDisplay()
が用いられることになります
親クラスGameCharacterのメンバ関数
statusDataDisplay()が
virtual void statusDataDisplay()=0;
も設定により
純粋仮想関数に設定されている場合でも
子クラスDragon型のオブジェクトPokkyのメンバ関数statusDataDisplay()
Pokky.statusDataDisplay();
が実行されるとき
親クラスGameCharacterのメンバ関数statusDataDisplay()でなく
子クラスDragonのメンバ関数statusDataDisplay()の定義
がもちいられることになります」
マックス「ちょっと ちょっと
お兄さん
それだと
別に
親クラスGameCharacterのメンバ関数を
純粋仮想関数宣言
virtual void statusDataDisplay()=0;
を実行して
純粋仮想関数に設定しなくてもいいんじゃないか
普通に
親クラスGameCharacterのメンバ関数statusDataDisplay()
と
子クラスDragonのメンバ関数statusDataDisplay()
の名前が一緒だと
オーバーライドがおこるからな
もっというと仮想関数にすら設定する必要もないじゃないか😊
それに今のプログラムの場合
純粋仮想関数宣言
virtual void statusDataDisplay()=0;
の
=0
を取り除いた
仮想関数宣言
virtual void statusDataDisplay();
を実行して
statusDataDisplay()
を
仮想関数に設定したとしても
同じビルド実行結果がえられるんじゃないか?」
そのプログラムはこちらとなります。
👇
#include <iostream>
#include <string>
using namespace std;
class GameCharacter {
public:
string name;
int HP;
int MP;
virtual void statusDataDisplay();
//🌞純粋仮想関数宣言を仮想関数宣言に変更してみました
};
class Dragon :public GameCharacter {
public:
int DP;//🌞ドラゴンポイントが設定されています
void statusDataDisplay();
};
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";
cout << "子クラスDragonのメンバ関数statusdatadisplay()が実行されました" << "\n";
}
int main() {
Dragon Pokky;
//👆PokkyのクラスDragon型のオブジェクト宣言をおこなっています
Pokky.name = "ポッキー";
Pokky.HP = 15;
Pokky.MP = 5;
Pokky.DP = 3;
/*👆子クラスDragonに親クラスGameCharacterの
メンバ変数宣言
string name;
int HP;
int MP;
が引き継がれています
そして
子クラスDragon型のオブジェクト宣言
Dragon Pokky;
により
生成される
子クラスDragon型のオブジェクトPokkyのメンバ変数
Pokky.name
Pokky.HP
Pokky.MP
にデータを代入しています*/
Pokky.statusDataDisplay();
return 0;
}
ビルド実行結果
重大度レベル コード 説明 プロジェクト ファイル 行 抑制状態
エラー LNK2001 外部シンボル ""public: virtual void __thiscall GameCharacter::statusDataDisplay(void)" (?statusDataDisplay@GameCharacter@@UAEXXZ)" は未解決です。
エラー LNK1120 1 件の未解決の外部参照
マックス「ビルド実行できて・・・いない・・・?
純粋仮想関数宣言
virtual void statusDataDisplay()=0;
を
仮想関数宣言
virtual void statusDataDisplay();
に変えただけなんだが
なぜだ??
どちらの場合でも
オーバライドが設定されるんだろう?
おっかしー」
ソーラー「そうなんです(*^_^*)が」
マックス「?」
ソーラー「仮想関数と純粋仮想関数のおもな違いとは
仮想関数では定義の記述が必要で
純粋仮想関数では定義の記述が必要でないということなんです。
だって
純粋に仮想な関数だからね。」
ぶーにゃん「にゃ~~~~ん(おさかな、おさかな どこかにいないかにゃ~)」
ソーラー「ですので
今のプログラムでは
仮想関数宣言
virtual void statusDataDisplay();
が実行されているものの
statusDataDisplay()
の定義が記述されていないため
ビルドエラーが生じたというわけです」
マックス「仮想関数は定義を記述しないと
ビルドエラーが生じ
純粋仮想関数は定義を記述しなくても
ビルドエラーが生じないというわけだ」
ソーラー「となると
今のプログラムでは
仮想関数宣言
virtual void statusDataDisplay();
が実行されているので
仮想関数statusDataDisplay()
の定義を
例えば
以下のように設定すれば
ビルドエラーは表示されなくなります
👇
void GameCharacter::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "親クラスGameCharacterのメンバ関数statusDataDisplay()が実行されました" << "\n";
}
そのことを示すプログラムはこちらです
👇
#include <iostream>
#include <string>
using namespace std;
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";
cout << "親クラスGameCharacterのメンバ関数statusDataDisplay()が実行されました" << "\n";
}
//🌞👆仮想関数の定義を設定しました
class Dragon :public GameCharacter {
public:
int DP;//🌞ドラゴンポイントが設定されています
void statusDataDisplay();
};
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";
cout << "子クラスDragonのメンバ関数statusDataDisplay()が実行されました" << "\n";
}
int main() {
Dragon Pokky;
//👆Pokkyの子クラスDragon型のオブジェクト宣言をおこなっています
Pokky.name = "ポッキー";
Pokky.HP = 15;
Pokky.MP = 5;
Pokky.DP = 3;
Pokky.statusDataDisplay();
return 0;
}
プログラムの実行結果
ポッキー
HP 15
MP 5
DP 3
子クラスDragonのメンバ関数statusDataDisplay()が実行されました
ソーラー「結局のところ
親クラスGameCharacterのメンバ関数
statusDataDisplay()が
純粋仮想関数でも
仮想関数でも
子クラスDragon型のオブジェクトのメンバ関数
(子クラスがポイントです)
Pokky.statusDataDisplay();
が実行されると
オーバーライドがおこり
子クラスDragonのメンバ関数statusDataDisplay()の定義が用いられることになります
ところで
このように
親クラスGameCharacterのメンバ関数
statusDataDisplay()
が
仮想関数に設定され
仮想関数の定義も記述されているとします
Pokkyの親クラスGameCharacter型のオブジェクト宣言
GameCharacter Pokky;
を実行して
💖親クラスGameCharacter型💖のオブジェクトPokky
を作製した場合
親クラスGameCharacter型のオブジェクトPokkyのメンバ変数
Pokky.name
Pokky.HP
Pokky.MP
親クラスGameCharacter型のオブジェクトPokkyのメンバ関数
Pokky.statusDataDisplay()
が生成されます。
親クラスGameCharacter型のオブジェクトPokkyのメンバ関数
Pokky.statusDataDisplay();
の実行においては
親クラスGameCharacter型のメンバ関数
statusDataDisplay()の定義がもちいられることになります
親クラスGameCharacter型のメンバ関数
statusDataDisplay()
が
子クラスDragon型のメンバ関数
statusDataDisplay()
によって
オーバーライドされていても
オーバーライドしている
子クラスDragonのメンバ関数
statusDataDisplay()の定義が用いられることはありません
それとは別に
親クラスGameCharacterのメンバ関数
statusdatadisplay()
が
純粋仮想関数宣言
virtual void statusdatadisplay()=0;
により
純粋仮想関数
に設定されていると
😊定義を記述することもしないこともできますが😊
😊定義が記述されているいないにかかわらず😊
Pokkyの親クラスGameCharacter型のオブジェクト宣言
GameCharacter Pokky;
を実行して
親クラスGameCharacter型のオブジェクトPokkyを生成するということができません
そのことを示すプログラムはこちらになります
👇
#include <iostream>
#include <string>
using namespace std;
class GameCharacter {
public:
string name;
int HP;
int MP;
virtual void statusDataDisplay()=0;
//🌞statusDataDisplay()の純粋仮想関数宣言を行っています
};
void GameCharacter::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "親クラスGameCharacterのメンバ関数statusdatadisplay()が実行されました" << "\n";
}
//🌞👆純粋仮想関数の定義を設定しました
class Dragon :public GameCharacter {
public:
int DP;//🌞ドラゴンポイントが設定されています
void statusDataDisplay();
};
void Dragon::statusDataDisplay() {
cout << name << "\n";
cout << "HP " << HP << "\n";
cout << "MP " << MP << "\n";
cout << "DP " << DP << "\n";
cout << "子クラスDragonのメンバ関数statusdatadisplay()が実行されました" << "\n";
}
int main() {
GameCharacter Pokky;
//👆PokkyのクラスGameCharacter型のオブジェクト宣言をおこなっています
Pokky.name = "ポッキー";
Pokky.HP = 15;
Pokky.MP = 5;
Pokky.statusDataDisplay();
return 0;
}
ビルドエラー
エラー (アクティブ) E0322 抽象クラス型 "GameCharacter" のオブジェクトは使用できません:
エラー C2039 'DP': 'GameCharacter' のメンバーではありません。
ソーラー「このように
親クラスのクラス宣言内で
純粋仮想関数宣言が設定されていると
親クラス型のオブジェクトを作製することはできなくなります」
マックス「結局のところ
親クラスGameCharacterのクラス宣言内で
純粋仮想関数宣言
virtual void statusDataDisplay()=0;
が実行されていると
statusDataDisplay()の定義が記述されているいないにかかわらず
Pokkyの親クラスGameCharacter型のオブジェクト宣言
GameCharacter Pokky;
を実行して
親クラスGameCharacter型のオブジェクトPokkyを生成することができないってわけだ
まあ
純粋仮想関数宣言
virtual void statusDataDisplay()=0;
が実行され
statusDataDisplay()が
純粋仮想関数
に設定されていると
statusDataDisplay()の定義を記述しなくてもよいので
Pokkyの親クラスGameCharacter型のオブジェクト宣言
GameCharacter Pokky;
を実行して
親クラスGameCharacter型のオブジェクトPokkyが生成できてしまうと
Pokky.statusdatadisplay();
の実行の際
定義内容が設定されていない
親クラスGameCharacterのメンバ関数statusDataDisplay()の定義が
もちいられることになるから
Pokkyの親クラスGameCharacter型のオブジェクト宣言
GameCharacter Pokky;
を実行して
親クラスGameCharacter型のオブジェクトPokkyを生成することができない
っていうシステムはなかなかいいんじゃないか?
おや
親クラスGameCharacter型のオブジェクトが作成できないってことは
親クラスGameCharacterはクラス単体では機能しないってわけか・・・
となると
必然的に
Pokkyの子クラスDragon型のオブジェクト宣言
Dragon Pokky;
を実行して
子クラスDragon型のオブジェクトPokkyを
作製するしかなくなるんじゃないか?」
ソーラー「そう、そう そうなんです
子クラスDragon型のオブジェクトPokkyを
作製するしかなくなるんです
子クラスDragon型のオブジェクト宣言
Dragon Pokky;
が実行されると
子クラスDragon型のオブジェクトPokkyのメンバ変数
Pokky.name
Pokky.HP
Pokky.MP
Pokky.DP
子クラスDragon型のオブジェクトPokkyのメンバ関数
Pokky.statusDataDisplay()
が
生成されます
そして
Pokky.statusDataDisplay();
が実行されるときは
親クラスGameCharacter のメンバ関数
statusDataDisplay()
が
子クラスDragonのメンバ関数
statusDataDisplay()
によって
オーバーライドされているので
子クラスDragonのメンバ関数
statusDataDisplay()
の定義がもちいられることになります
オーバーライドがおきるというわけです。
このように
クラスのメンバ関数が
1つでも
定義内容を記述しなくてもよい純粋仮想関数に設定されているクラスを
抽象クラスといいます
」
マックス「メンバ関数の定義内容が記述されていないと
何をしようとしているクラスかわからないじゃないか?
そうか(#^^#)
だから
抽象クラス
ってわけか」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます