🌞親クラスの仮想メンバ関数を子クラスのメンバ関数によってオーバーライドすることにより親クラス型のオブジェクトを通して子クラス型のオブジェクトのメンバ変数に格納されているデータを変更することができます🌞

親クラス*型のポインタ変数->オーバーライドされたメンバ関数を用いて子クラス型のオブジェクトのメンバ変数に格納されているデータを変更することができます まるでカプセル化のようです


ソーラー「


子クラス型のオブジェクトのアドレスを


親クラス*型のポインタ変数に代入した場合


親クラス*型のポインタ変数にアロー演算子->を用いた



親クラス*型のポインタ変数->子クラスの()メンバ変数


親クラス*型のポインタ変数->子クラスの()メンバ関数



子クラス型のオブジェクトの()メンバ変数

子クラス型のオブジェクトの()メンバ関数


の管理するメモリ領域にアクセスすることができました


そして


親クラス*型のポインタ変数->子クラスの(子クラスに元から備わっている)メンバ変数


親クラス*型のポインタ変数->子クラスの(子クラスに元から備わっている)メンバ関数


では


子クラス型のオブジェクトの(子クラスに元から備わっている)メンバ変数

子クラス型のオブジェクトの(子クラスに元から備わっている)メンバ関数


の管理するメモリ領域にアクセスすることはできませんでした


ですが


親クラスのメンバ関数が仮想関数に設定されていて


子クラスのメンバ関数によって


オーバーライドされている場合



親クラス*型のポインタ変数にアロー演算子->を用いた


親クラス*型のポインタ変数->子クラスの(子クラスに元から備わっている)メンバ関数


を用いて


子クラス型のオブジェクトの(子クラスに元から備わっている)メンバ関数


の管理するメモリ領域にアクセスすることができました


そして


親クラス*型のポインタ変数->子クラスの(子クラスに元から備わっている)メンバ関数


を用いて


子クラス型のオブジェクトの(子クラスに元から備わっている)メンバ関数


の管理するメモリ領域にアクセスすることができるということは


親クラス*型のポインタ変数->子クラスの(子クラスに元から備わっている)メンバ関数


を実行した場合


子クラス型のオブジェクトの(子クラスに元から備わっている)メンバ関数


を実行できるということなんです


親クラス*型のポインタ変数->子クラスの(子クラスに元から備わっている)メンバ関数


を実行する


つまり



子クラス型のオブジェクトの(子クラスに元から備わっている)メンバ関数


が実行される際



          🌞間接的に🌞



子クラス型のオブジェクトの(親クラスから引き継いだ)メンバ変数

子クラス型のオブジェクトの(子クラスに元から備わっている)メンバ変数


に  

 

格納されているデータを変更することができるんです



今日はそのことについて学んでみたいとおもいもいます」



マックス「なんじゃ こりゃ ええっ・・・??



子クラス型のオブジェクトのアドレスを


親クラス*型のポインタ変数に代入したんだろう


本来なら


子クラス型のオブジェクトのアドレス



子クラス*型のポインタ変数に代入するのが


普通なんだが


子クラス型のオブジェクトのアドレスを


親クラス*型のポインタ変数に代入したんだろう



子クラス型のオブジェクトのアドレス



子クラス*型のポインタ変数に代入した場合



親クラス*型のポインタ変数に代入した場合では


違いが出るんだったな😊」




ソーラー「そうなんです まずは次のプログラムをご覧ください


#include <iostream>

#include <string>//文字列を取り扱うためにヘッダファイル <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";


}




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

DP = 8;

cout << "DP " << DP << "\n";

}




int main() {


GameCharacter* pta;


Dragon Pokky;

Pokky.name = "ポッキー";

Pokky.HP = 20;

Pokky.MP = 3;

Pokky.DP = 2;


pta = &Pokky;


pta->DP;

pta->statusDataDisplay();



return 0;

}



ビルド実行結果


重大度レベル コード 説明 プロジェクト ファイル 行 抑制状態

エラー C2039 'DP': 'GameCharacter' のメンバーではありません。

エラー (アクティブ) E0135 class "GameCharacter" にメンバー "DP" がありません



ソーラー「このプログラムでは


GameCharacter* pta;


の実行により


親クラスGameCharacter* 型のポインタ変数ptaが生成されています


次に


Pokkyの子クラスDragon型のオブジェクト宣言


Dragon Pokky;


を実行し


子クラスDragon型のオブジェクトPokkyを生成しています


すると同時に


子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.name

Pokky.HP

Pokky.MP

Pokky.DP


が生成されることになります


その際


main関数内で


子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.name

Pokky.HP

Pokky.MP

Pokky.DP


を用いて


Pokky.name = "ポッキー";

Pokky.HP = 20;

Pokky.MP = 3;

Pokky.DP = 2;


を実行し


子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.name

Pokky.HP

Pokky.MP

Pokky.DP


にデータを代入することができます


main関数内で


子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.name

Pokky.HP

Pokky.MP

Pokky.DP


にアクセスすることができるというわけです


このとき


もちろん


子クラスDragon型のオブジェクトPokkyのメンバ関数


Pokky.statusDataDisplay()


も生成されています



子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.name

Pokky.HP

Pokky.MP

Pokky.DP


の管理しているメモリ領域と


子クラスDragon型のオブジェクトPokkyのメンバ関数


Pokky.statusDataDisplay()


の管理しているメモリ領域


が生成されていることになるね


このプログラムでは


次に


ptaの親クラスGameCharacter* 型のポインタ変数宣言


GameCharacter* pta;


によって作成された


親クラスGameCharacter* 型のポインタ変数ptaに


子クラスDragon型のオブジェクトPokkyのアドレス&Pokky


を代入しています





親クラスGameCharacter* 型のポインタ変数ptaにアロー演算子を用いた


pta->に


親クラスGameCharacterのメンバ変数


name

HP

MP


をくっつけた


pta->name

pta->HP

pta->MP


親クラスGameCharacter* 型のポインタ変数ptaにアロー演算子を用いた


pta->に


親クラスGameCharacterのメンバ関数


statusDataDisplay()


をくっつけた


pta->statusDataDisplay()


では


子クラスDragon型のオブジェクトPokkyの(親クラスから引き継いだ)メンバ変数


Pokky.name

Pokky.HP

Pokky.MP


子クラスDragon型のオブジェクトPokkyの(親クラスから引き継いだ)メンバ関数

Pokky.statusDataDisplay()


にアクセスすることはできても



親クラスGameCharacter* 型のポインタ変数ptaにアロー演算子を用いた


pta->に


子クラスDragonのメンバ変数


DP


をくっつけた


pta->DP



pta->に


DragonstatusDataDisplay()


をくっつけた


pta->statusDataDisplay()


では


子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.DP


子クラスDragon型のオブジェクトPokkyのメンバ関数


Pokky.statusDataDisplay()


の管理するメモリ領域にアクセスすることはできません


そもそも


親クラスGameCharacter* 型のポインタ変数ptaにアロー演算子を用いた


pta->にくっつけることができるのは


親クラスGameCharacterから引き継いだメンバ変数


name

HP

MP


親クラスGameCharacterから引き継いだメンバ関数


statusDataDisplay()


だけです


子クラスDragonのメンバ変数


DP


をくっつけた


pta->DP



pta->に


DragonstatusDataDisplay()


をくっつけた


pta->statusDataDisplay()


は存在しません



ここで


pta->DP;


を取り除いたプログラムを実行してみたいと思います


そのプログラムはこちらです

👇


#include <iostream>

#include <string>//文字列を取り扱うためにヘッダファイル <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";


}




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

DP = 8;

cout << "DP " << DP << "\n";

}




int main() {


GameCharacter* pta;




Dragon Pokky;

Pokky.name = "ポッキー";

Pokky.HP = 20;

Pokky.MP = 3;

Pokky.DP = 2;


pta = &Pokky;



pta->statusDataDisplay();


return 0;

}


プログラムの実行結果


ポッキー

HP 20

MP 3

DP 8


マックス「なんだ プログラムが実行できている


なんでぇ?


pta->statusDataDisplay();


が実行されているようだが・・・



プログラムの実行結果をみると・・・


ポッキー

HP 20

MP 3

DP 2


でなく


ポッキー

HP 20

MP 3

DP 8


になっている・・・


これは・・・


ううん??


子クラスDragonのメンバ関数の定義

👇

void Dragon::statusDataDisplay() {


cout << name << "\n";

cout << "HP " << HP << "\n";

cout << "MP " << MP << "\n";

DP = 8;

cout << "DP " << DP << "\n";

}


👆



DP = 8;


の影響か?


おお うおおおおおおおおおおおおおおおおおおおおおおおおおおおお


          分かったI understand


にゃ( ̄∇ ̄;)ハッハッハ



このプログラムでは



          🌞🌞🌞仮想関数である🌞🌞🌞



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



子クラスDragonのメンバ関数statusDataDisplay()


によって


        🌞オーバーライドされている🌞


だから


親クラスGameCharacter* 型のポインタ変数pta



子クラスDragon 型のオブジェクトPokkyのアドレス&Pokky


を代入し



親クラスGameCharacter* 型のポインタ変数ptaに


アロー演算子->がくっつけられた


pta->に


statusDataDisplay()


をくっつけた


pta->statusDataDisplay();


が実行されると


親クラスGameCharacterのメンバ関数


statusDataDisplay()


の定義でなく


子クラスDragonのメンバ関数


statusDataDisplay()


の定義が用いられることになるってわけだ



やはり


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



    🌞🌞🌞仮想関数に設定されているので🌞🌞🌞



親クラスGameCharacter* 型のポインタ変数ptaに


アロー演算子->がくっつけられた


pta->に


statusDataDisplay()


をくっつけた


pta->statusDataDisplay()



子クラスDragon型のオブジェクトPokkyのメンバ関数


Pokky.statusDataDisplay()の管理しているメモリ領域に


アクセスしているようじゃんか」



ソーラー「その通り


pta->statusDataDisplay();


が実行されると


子クラスDragon型のオブジェクトPokkyのメンバ関数


Pokky.statusDataDisplay()の管理しているメモリ領域に


アクセスする


すなわち


子クラスDragon型のオブジェクトPokkyのメンバ関数


Pokky.statusDataDisplay()


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


マックス「やはり、そうか



ここで面白いことが起こる


main関数内で


親クラスGameCharacter* 型のポインタ変数ptaに


アロー演算子->がくっつけられた


pta->に


子クラスDragonのメンバ変数DPが用いられた


         pta->DP


は実行できなかった


つまり


         pta->DPでは


子クラスDragon型のオブジェクトのメンバ変数


Pokky.DP

の管理しているメモリ領域にアクセスすることはできないってわけだ


だから


子クラスDragon型のオブジェクトのメンバ変数


Pokky.DP


に格納されているデータを



        pta->DPを用いて



           直接


変更することはできない



だが



親クラスGameCharacter* 型のポインタ変数ptaに


アロー演算子->がくっつけられた


pta->に


子クラスDragonのメンバ関数statusDataDisplay()が用いられた



pta->statusDataDisplay();


が実行されると



子クラスDragonのメンバ関数statusDataDisplay()の定義

👇

void Dragon::statusDataDisplay() {


cout << name << "\n";

cout << "HP " << HP << "\n";

cout << "MP " << MP << "\n";

DP = 8;

cout << "DP " << DP << "\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";

Pokky.DP = 8;

cout << "DP " << Pokky.DP << "\n";


が実行されることになる



ふははははははは



つまりだ


親クラスGameCharacter* 型のポインタ変数ptaに


アロー演算子->がくっつけられた


pta->に


子クラスDragonのメンバ関数statusDataDisplay()が用いられた



pta->statusDataDisplay();


が実行されるということは


        この場合(親クラスのメンバ関数は仮想関数に設定されているので)


子クラスDragon型のオブジェクトPokkyの(子クラスに元から備わっている)メンバ関数statusDataDisplay()


Pokky.statusDataDisplay()が実行されるということであり



子クラスDragon型のオブジェクトPokkyのメンバ関数


Pokky.statusDataDisplay()を通して


子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.name

Pokky.HP

Pokky.MP

Pokky.DP👈👈👈ここが注目ポイントです



に格納されているデータを



変更することができるってわけだ


      どうだ??


きまった・・・・・」



てんC「お見事です!!😊マックスさん!」




ソーラー「そうなんです


親クラスGameCharacter*型のポインタ変数ptaに


アロー演算子->


がくっつけられた


pta->に


子クラスDragonのメンバ変数DPが用いられた


pta->DP



main関数内で用いて


子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.DPの管理しているメモリ領域に


直接アクセスすることは


できませんが


親クラスGameCharacter*型のポインタ変数ptaに


アロー演算子->


がくっつけられた


pta->に


statusDataDisplay()が用いられた


pta->statusDataDisplay()



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


statusDataDisplay()がオーバーライドされていることにより


子クラスDragon型のオブジェクトPokkyのメンバ関数


Pokky.statusDataDisplay()の管理しているメモリ領域に


          アクセスすることになります


子クラスDragon型のオブジェクトPokkyのメンバ関数


Pokky.statusDataDisplay()を通してなら


すなわち


Pokky.statusDataDisplay()の管理しているメモリ領域からなら


子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.name

Pokky.HP

Pokky.MP

Pokky.DP👈👈👈ここが注目ポイントです


に格納されているデータを変更することができるというわけです



        そう


pta->statusDataDisplay()


が実行されると


子クラスDragonのメンバ関数statusDataDisplay()の定義

👇

void Dragon::statusDataDisplay() {


cout << name << "\n";

cout << "HP " << HP << "\n";

cout << "MP " << MP << "\n";

DP = 8;

cout << "DP " << DP << "\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";

Pokky.DP = 8;

cout << "DP " << Pokky.DP << "\n";



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



ですので


最初


子クラスDragon型のオブジェクトPokkyのメンバ変数DP


Pokky.DP


には


Pokky.DP = 2;


より


2


が代入されていますが


pta->statusDataDisplay();


の実行により


子クラスDragon型のオブジェクトPokkyのメンバ変数DP


Pokky.DP


に格納されている値は


8に変化するというわけです


その気になれば


子クラスDragonのメンバ関数の定義を変更すれば


pta->statusDataDisplay();


の実行により


子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.DPだけでなく





     🌞子クラスDragon型のオブジェクトPokky💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖🌞のメンバ変数

Pokky.name

Pokky.HP

Pokky.MP

Pokky.DP


格納されているデータを


変更することも可能です


どう?



簡単だったかな?」



てんC「このことは


           pta->DP


を用いて


子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.DP


に格納されているデータを変更できないのに



pta->statusDataDisplay();


を用いてなら


子クラスDragon型のオブジェクトPokkyのメンバ変数


Pokky.DP


に格納されているデータを変更することができることを


あらわしています


まるで


     カプセル化のようです」

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

作者を応援しよう!

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

応援したユーザー

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

新規登録で充実の読書を

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

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

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