代入演算子=のオーバーロードを実行してみます その1

つづき・・・



ソーラー「代入演算子=のオーバーロードを実行してみよう!


実は・・・


代入演算子=のオーバーロードを実行するには


クラスに


クラスのメンバ関数operator=を設定する方法しか


ありません


代入演算子=のオーバーロードを実行するのに


クラスのメンバ関数ではない


普通の自作関数operator=を設定する方法はありません



ですので


クラスのメンバ関数operator=を設定する方法で


代入演算子=のオーバーロードを実行してみます


例えば次のような


数値データと文字列データを取り扱うオブジェクトを生成するための


クラスSuutitoMojiがあるとします

👇

class SuutitoMoji{


public:


int x;


public:


char* i;//ポインタ変数iを用いて文字列データをメモリに格納することができます



};



このクラスSuutitoMojiに


クラスのメンバ関数operator=を設定してみます


そのためには


SuutitoMojiのクラス宣言内で


operator=関数のメンバ関数宣言


SuutitoMoji operator=(SuutitoMoji& c);


を記述し


operator=関数の定義

👇

SuutitoMoji::SuutitoMoji operator=(SuutitoMoji& c){


x = c.x;


i = new char[50];


strcpy_s(i, 50, c.i);

}


を記述することになります


その様子は以下のようになります

👇


class SuutitoMoji{


public:


int x;


public:


char* i;


public:


SuutitoMoji operator=(SuutitoMoji& c);


};



SuutitoMoji SuutitoMoji::operator=(SuutitoMoji& c) {


x = c.x;


i = new char[50];


strcpy_s(i, 50, c.i);


return *this;

}


//👆🌞operator=関数の定義です

👆


このように設定されたクラスSuutitoMoji



クラスSuutitoMojiのメンバ関数operator=の定義を用いて


プログラムを実行してみます


👇


#include <iostream>


using namespace std;


class SuutitoMoji{


public:


int x;


public:


char* i;


public:


SuutitoMoji operator=(SuutitoMoji& c);


};


SuutitoMoji SuutitoMoji::operator=(SuutitoMoji& c) {


x = c.x;


i = new char[50];


strcpy_s(i, 50, c.i);


return *this;

}



int main() {


SuutitoMoji a;


SuutitoMoji b;


b.x = 1;

b.i = new char[50];


strcpy_s(b.i, 50, "にゃこ");


a = b;


cout << (a.operator=(b)).x << "\n";

cout << (a.operator=(b)).i << "\n";



cout << (a = b).x << "\n";

cout << (a=b).i << "\n";


cout << a.i << "\n";

cout << b.i << "\n";


delete b.i;


cout << a.i << "\n";

cout << b.i << "\n";



return 0;

}


ビルド実行結果

1

にゃこ

1

にゃこ

にゃこ

にゃこ

にゃこ

ンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンン)r・gチウ



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


bのクラスSuutitoMoji型のオブジェクト宣言


SuutitoMoji b;


を実行して


クラスSuutitoMoji型のオブジェクトbを作製し


生成される


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.xに


b.x = 1;


を実行して


1を代入しています


そして


b.i = new char[50];


を実行することにより


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iを用いて


動的にメモリ領域を確保しています


このとき


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iには


動的に確保したメモリ領域の先頭のメモリのアドレスが


代入されることになります


動的に確保したメモリ領域に文字列データを格納するには


strcpy_s関数を用いるのでしたね


strcpy_s(b.i,50, "にゃこ");


が実行されると


b.iによって動的に確保されたメモリ領域に


文字列データ


"にゃこ"


が格納されることになります


このとき


クラスSuutitoMoji型のオブジェクトaをクラスSuutitoMoji型のオブジェクトbで初期化する


            🌞 a = b;🌞


が実行されると


クラスSuutitoMoji型のオブジェクトaのメンバ関数である


           🌞a.operator=(b);🌞


が実行されます


つまり


             🌞 a = b;🌞




           🌞a.operator=(b);🌞


が実行されることと等しいのです  


a.operator=(b);


が実行されると   


クラスSuutitoMojiのメンバ関数であるoperator=関数の定義

👇


SuutitoMoji SuutitoMoji::operator=(SuutitoMoji& c) {


x = c.x;


i = new char[50];


strcpy_s(i, 50, c.i);


return *this;

}



SuutitoMoji& c



クラスSuutitoMoji型のオブジェクトbが


代入されて


xにはa.x


iにはa.i


が代入された状態の

a.x = b.x;


a.i = new char[50];


strcpy_s(a.i, 50, b.i);


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


a.x = b.x;


が実行されると


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.xに


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.xが代入され


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.xの格納している数値データ1が代入されますね



a.i = new char[50];


が実行されると


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iによって


動的にメモリ領域が確保されます



このとき


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iには


動的に確保したメモリ領域の先頭のメモリのアドレスが


代入されることになります



次に


strcpy_s(a.i, 50, b.i);


が実行されると


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iの格納しているアドレスのメモリを先頭とするメモリ領域


つまり


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iによって動的に確保されたメモリ領域



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iの格納しているアドレスのメモリを先頭とするメモリ領域


つまり


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iによって動的に確保されたメモリ領域


に格納されている文字列データ


"にゃこ"


が格納されることになります


よ~く観察すると


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


を用いて


b.i = new char[50];


を実行して


動的にメモリ領域を確保し



クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i


を用いて


a.i = new char[50];


を実行して


動的にメモリ領域を確保しているので


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iが格納している



         💖アドレスは異なることがわかります💖



アドレスは異なっているのですが


strcpy_s(a.i, 50, b.i);


が実行されることにより


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iの格納しているアドレスのメモリを先頭とするメモリ領域


つまり


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iによって動的に確保されたメモリ領域



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iの格納しているアドレスのメモリを先頭とするメモリ領域


つまり


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iによって動的に確保されたメモリ領域


には


ともに


             💖同じ文字列データ💖


                "にゃこ"


が格納されることになります


次に


return *this;


が実行されます


いま


               a = b;


すなわち


クラスSuutitoMoji型のオブジェクトa💖のメンバ関数


a💖.operator=(b);


が実行されているので


thisはクラスSuutitoMoji型のオブジェクトaのアドレスを格納したポインタ変数を表しています


ですので


*thisは


クラスSuutitoMoji型のオブジェクトaを表すことになります


つまり


return *this;


が実行されると



a.operator=(b)


イコール


a=b


に戻り値として


クラスSuutitoMoji型のオブジェクトa


が返されることになります



operator=関数の定義

👇

SuutitoMoji SuutitoMoji::operator=(SuutitoMoji& c) {


x = c.x;


i = new char[50];


strcpy_s(i, 50, c.i);


return *this;

}


を観察すると


クラスSuutitoMojiのメンバ関数operator=関数の戻り値を格納する型は


SuutitoMoji


となっています


ですので





クラスSuutitoMoji型のオブジェクトaのメンバ関数


a.operator=(b)


イコール


a=b


に戻り値として


クラスSuutitoMoji型のオブジェクトaが


返されることになります


a.operator=(b)


イコール


a=b



クラスSuutitoMoji型のオブジェクトを表しているんです


驚きだね😊!


a.operator=(b)


イコール


a=b



クラスSuutitoMoji型のオブジェクトなので


クラスSuutitoMoji型のオブジェクトa.operator=(b)のメンバ変数


(a.operator=(b)).x

(a.operator=(b)).i


つまり

クラスSuutitoMoji型のオブジェクトa=bのメンバ変数


(a=b).x

(a=b).i


が存在することになります


クラスSuutitoMoji型のオブジェクトaのメンバ関数


a.operator=(b)


イコール


a=b


に戻り値として


クラスSuutitoMoji型のオブジェクトaが


返されるのですが


この場合は


a.xには数値データ1


a.iには"文字列データ"にゃこ"を格納している動的に確保されたメモリ領域の先頭のアドレス



が格納されているので


クラスSuutitoMoji型のオブジェクトであるa.operator=(b)のメンバ変数


(a.operator=(b)).x

(a.operator=(b)).i


つまり


クラスSuutitoMoji型のオブジェクトであるa=bのメンバ変数


(a=b).x

(a=b).i


に戻り値として


a.xに格納されている数値データ1


a.iに格納されている文字列データ"にゃこ


が戻り値として返されることになります


ですので


続く命令文


cout << (a.operator=(b)).x << "\n";

cout << (a.operator=(b)).i << "\n";


cout << (a = b).x << "\n";

cout << (a=b).i << "\n";


が実行されると


1

にゃこ

1

にゃこ


がコマンドプロンプト画面に表示されることになります



次に


cout << a.i << "\n";

cout << b.i << "\n";


が実行されると


cout << a.i << "\n";

cout << b.i << "\n";

(アドレスを表示するのではなくアドレス番号のついたメモリに格納されたデータを表示することになります)


a.iが格納しているアドレスのメモリを先頭とするメモリ領域に格納されている文字列データ

つまり

a.iによって動的に確保されたメモリ領域に格納されている文字列データ



b.iが格納しているアドレスのメモリを先頭とするメモリ領域に格納されている文字列データ


つまり

b.iによって動的に確保されたメモリ領域に格納されている文字列データ




コマンドプロンプト画面に表示する命令文なので



にゃこ

にゃこ



コマンドプロンプト画面に表示されることになります



次に


delete b.i;


の実行により


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iによって動的に確保されたメモリ領域は解放されることになります


すると


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i


消去されませんが


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iによって動的に確保されたメモリ領域に格納された文字列データ


"にゃこ"



メモリから消去されることになります


ですので


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iによって動的に確保されたメモリ領域は何もデータが代入されていない状態となります


delete b.i;


が実行されても


もちろん


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iによって動的に確保されたメモリ領域が解放されることはなく


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iによって動的に確保されたメモリ領域には


文字列データ


"にゃこ"



格納されたままですね


もちろん


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iは


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iによって動的に確保されたメモリ領域の先頭のメモリのアドレスを格納しています


ですので


続く命令文


cout << a.i << "\n";

cout << b.i << "\n";


が実行されると


cout << a.i << "\n";


a.iが格納しているアドレスのメモリを先頭とするメモリ領域に格納されている文字列データ

つまり

a.iによって動的に確保されたメモリ領域に格納されている文字列データ



コマンドプロンプト画面に表示する命令文なので


にゃこ


コマンドプロンプト画面に表示されます


次に


cout << b.i << "\n";


が実行されます


cout << b.i << "\n";


b.iが格納しているアドレスのメモリを先頭とするメモリ領域に格納されている文字列データを


コマンドプロンプト画面に表示する命令文なのですが


b.iが格納しているアドレスのメモリを先頭とするメモリ領域には何もデータが代入されていない状態なので


cout << b.i << "\n";

が実行されると


b.iが格納しているアドレスのメモリを先頭とするメモリ領域に何もデータが代入されていないときに


b.iが格納しているアドレスのメモリを先頭とするメモリ領域に


格納されているデータ


ンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンン)r・gチウ



コマンドプロンプト画面に表示されることになります



これで目的の


クラスSuutitoMojiのメンバ関数としてoperator=関数を


クラスSuutitoMojiに設定することにより


つまり


    代入演算子=のオーバーロードを実行することにより




a = b;


が実行されたとき


a.x

b.x

同じ数値データ1を



a.i

b.i

がそれぞれ異なるアドレスを持つようにすることがすることができるようになったね



 代入演算子=のオーバーロードを実行しなければ


a = b;


が実行されたとき


a.x

b.x

同じ数値データ1を



a.i

b.i

が同じアドレスを持つことになるよね」


マックス「なにぃ


目的を完全にわすれていたんだよぉ~~~んん


おおっぅ いつのまにやら


a = b;


が実行されたとき


a.x

b.x

同じ数値データ1を



a.i

b.i

がそれぞれ異なるアドレスを持つようにすることができている・・・!


なんかすごいな・・・


a = b;


を実行しているのにな・・・」











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

作者を応援しよう!

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

応援したユーザー

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

新規登録で充実の読書を

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

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

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