代入演算子=のオーバーロードを実行する その2 クラスのメンバ関数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はクラスSuutitoMoji型のオブジェクトaで


operator=は関数名


(b)



operator=関数の引数部分で


クラスSuutitoMoji型のオブジェクトbが代入されています)




つまり


            🌞 a = 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型のオブジェクトaのメンバ変数a.i

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


を用いて


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


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


が実行されます


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


a💖.operator=(b);が実行されたとき


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


ですので


thisにアスタリスク*を用いた


*thisは


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


つまり


return *this;


が実行されると


引数にクラスSuutitoMoji型のオブジェクトbが代入された


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


           🌞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には文字列データ"にゃこ"を格納している動的に確保されたメモリ領域の先頭のアドレス


が格納されているので


a.operator=(b)のメンバ変数


(a.operator=(b)).x

(a.operator=(b)).i


つまり


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によって動的に確保されたメモリ領域に格納された文字列データ

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


(a.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が格納しているアドレスのメモリを先頭とするメモリ領域に格納されている文字列データを


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


にゃこ

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


次に


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

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



マックス「いい感じじゃないか~😊」



ソーラー「ただ


クラスSuutitoMojiに


このように


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


設定した場合


a=a;


を実行すると


警告文が表示されることになります


つまり


いまのクラス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;


a.x = 1;

a.i = new char[50];


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


a = a;//👈🌞ここに注目!


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


delete a.i;


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

return 0;

}


ビルド実行結果


Debug Assertion Failed!


program

c\users\solarplexuss\source\repos\Project30\Debug\Project30.exe

File:minkernel\crts\ucrt\inc\corect_internal_string_templates.h

Line: 81


Expression: (L"Buffer is too small" && 0)


For information on how your program can cause an assertion

failure,see the Visual C++ documentation on assserts.


(Press Retry to debug the application)




中止(A)    再試行(R)     無視(I)


マックス「今日も元気にバグってるな~😊



        元気ですか~~~~~😊



                            」



int(イント)「ばう、ばう」




🌞    🌞    🌞    🌞    🌞    🌞



           ばう、ばう


🌞    🌞    🌞    🌞    🌞    🌞



てんC「元気です😊」



ソーラー「ではなぜ このプログラムを実行すると警告文が表示されるのかを見ていきましょう」


マックス「よっしゃ~一丁いくか!」



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


まず


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


SuutitoMoji a;


を実行してオブジェクトaを作製し


a.x = 1;


により


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.xに1を代入しています


そして


a.i = new char[50];


を実行することにより


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


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


このとき


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iには動的に確保したメモリ領域の先頭のメモリのアドレスが


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


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


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


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


が実行されると


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


文字列データ


"にゃこ"


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


              このとき


クラスSuutitoMoji型のオブジェクトaにクラスSuutitoMoji型のオブジェクトaを代入する


              😊 a = a;😊


を実行すると


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


a.operator(a);


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


つまり


クラス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型のオブジェクトaが


xにa.x


iにa.i


が代入された


a.x = a.x;


a.i = new char[50];


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


return *this;


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


ここが問題点なんです」


マックス「なんでぇだ?」


ソーラー「


なぜなら


最初


SuutitoMoji a;


a.x = 1;

a.i = new char[50];


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


が実行されたときに


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


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


動的に確保されたメモリ領域に


文字列データ"にゃこ"が格納されています


さらに


a=a;


が実行されると


a.x = a.x;


a.i = new char[50];


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


return *this;



実行されるのですが


このとき


ふたたび


a.i = new char[50];


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


すると


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


新たに動的にメモリ領域が確保されることになりますが


そのとき


動的に確保されたメモリ領域は何も文字列データが格納されていない


状態となります


もちろん


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


新たに動的に確保されたメモリ領域の先頭のメモリのアドレスが代入されることになりますので



           💖最初に💖


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


        💖動的に確保されたメモリ領域💖



つまり


文字列データ"にゃこ"を


格納したメモリ領域



クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iを用いてアクセスすることができなくなります


コンピュータのメモリの中に


アクセスすることのできない


文字列データ"にゃこ"を格納したメモリ領域が取り残されてしまうというわけです



  💖同じポインタ変数名を用いて動的にメモリ領域を確保する場合は



アクセスできないメモリ領域が取り残されるという点に注意が必要💖



というわけだね




その状態で


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


を実行しようとすると


なにもデータが格納されていない初期化されていない


新たにa.iによって動的に確保されたメモリ領域のデータを


なにもデータが格納されていない初期化されていない


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


に格納することになります(笑)


Visual Studioではそのようなことを実行しようとすると


警告文が表示されるという仕組みになっています」


マックス「なるほど


a=a;


が実行されるときは


そのようなことがおこるわけか・・・


そもそも


a=a;


っていうのは


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


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



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


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


の格納している値が代入されるということなんだろう?


a=a;


を実行するまでもなく


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


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


には


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


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


の格納している値が代入されているんじゃないか?


というか・・・




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


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


つまり


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


a = b;


が実行されたとき


a.x

b.x

同じ数値データ1を



a.i

b.i

がそれぞれ異なるアドレスを持つようにできるようになったんだろう?


だったら


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


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


つまり


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


a=a;


を実行して


a.operator(a);


を実行したとき


a.x

a.x

同じ数値データ1を



a.i

a.i

がそれぞれ異なるアドレスを持つようにできるようになる???


なんてなんかおかしくないか?



ソーラー「そうなんです


この代入演算子の定義では


a=b;


すなわち


a.operator(b);


を実行したとき


は問題ないのですが


a=a;


すなわち


a.operator(a);


を実行したとき


に問題が出てくるんです


このように


クラスSuutitoMoji型のオブジェクトaに自分自身であるクラスSuutitoMoji型のオブジェクトaを代入する場合も


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


a.operator(a);


が実行されることになるのですが


不具合が生じないよう


クラスのメンバ関数operator=の定義を


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


x = c.x;


i = new char[50];


strcpy_s(i, 50, c.i);


return *this;

}


から


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


if(this!=&c){

x = c.x;


i = new char[50];


strcpy_s(i, 50, c.i);


return *this;

}


else{


x=c.x;

i=c.i;


return *this;

}


}

のように


変更します


クラスSuutitoMoji型のオブジェクトaに同じクラスSuutitoMoji型のオブジェクトaを代入する


a=a;


を実行した場合


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


a.operator(a);


が実行されることになるのですが


そのとき


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

👇


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


if(this!=&c){

x = c.x;


i = new char[50];


strcpy_s(i, 50, c.i);


return *this;

}


else{


x=c.x;


i=c.i;


return *this;

}


}



SuutitoMoji& c


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


xにa.x

iにa.i



代入された


if(this!=&c){

a.x = a.x;


a.i = new char[50];


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


return *this;

}


else{


a.x=a.x;


a.i=a.i;


return *this;

}



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


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


a💖.operator(a);


が実行される


このとき


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


そして


ここでの


注目ポイントは


SuutitoMoji& c


にクラスSuutitoMoji型のオブジェクトaが代入されたという点です


SuutitoMoji& c


にクラスSuutitoMoji型のオブジェクトaが代入されると



    💖参照変数cはクラスSuutitoMoji型のオブジェクトaそのもの💖を


表すことになります


そうなると


クラスSuutitoMoji型のオブジェクトaのアドレス&aは


&cで表すこともできるようになります


つまり


&cは&aに等しくなります


ですので


if(this!=&c){

a.x = a.x;


a.i = new char[50];


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


return *this;

}


else{

a.x=a.x;

a.i=a.i;


return *this;

}




ここに👇注目です

if(this!=&a💖💖){

a.x = a.x;


a.i = new char[50];


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


return *this;

}


else{

a.x=a.x;

a.i=a.i;

}


を表すことになります


if(this!=&a){

a.x = a.x;


a.i = new char[50];


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


return *this;

}


else{

a.x=a.x;

a.i=a.i;


return *this;

}



            this!=&a


つまり


     ポインタ変数thisの格納しているアドレスが&aでなければ


if(this!=&a){

a.x = a.x;


a.i = new char[50];


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


return *this;

}


のブロック{}内の命令文


a.x = a.x;


a.i = new char[50];


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


return *this;


が実行され



            this=&a


つまり


    ポインタ変数thisの格納しているアドレスが&aであれば


else{

a.x=a.x;

a.i=a.i;


return *this;

}


のブロック{}内の命令文


a.x=a.x;

a.i=a.i;


return *this;


が実行される命令文になります




a=a;


つまり


a.operator(a);


が実行される場合


 ポインタ変数thisの格納しているアドレスは&aであり


            this=&a


であるので


a.x=a.x;

a.i=a.i;


return *this;


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


a.x=a.x;

a.i=a.i;


が実行されると


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


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


には


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


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


の格納しているデータが代入されることになります



a=a;


つまり


a.operator(a);


が実行される場合


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


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


には


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


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


の格納しているデータが代入されるという状態は



       😊何も問題なし😊


ですね



なお


return *this;


が実行されると


a=a


つまり


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


a.operator=(a)


には


戻り値として


*this


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


この場合


thisはオブジェクトaのアドレスを格納しているポインタ変数なので


*thisはオブジェクトaを表すことになります


return *this;


が実行されると


a=a


つまり


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


a.operator=(a)


には


戻り値として


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


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


ですので


a=a


つまり


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


a.operator=(a)



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


さて


それでは


クラスSuutitoMojiのメンバ関数operator=の定義が


👇

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


if(this!=&c){

x = c.x;


i = new char[50];


strcpy_s(i, 50, c.i);


return *this;

}


else{


x=c.x;

i=c.i;


return *this;

}

}


👆のように設定されたプログラムを実行してみたいと思います


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

👇


#include <iostream>


using namespace std;


class SuutitoMoji{


public:


int x;


public:


char* i;


public:


SuutitoMoji operator=(SuutitoMoji& c);


};


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


if (this != &c) {

x = c.x;


i = new char[50];


strcpy_s(i, 50, c.i);


return *this;

}


else {


x = c.x;

i = c.i;


return *this;

}


}


int main() {


SuutitoMoji a;


a.x = 1;

a.i = new char[50];


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


a = a;


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

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



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

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



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


delete a.i;


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


return 0;

}


プログラムの実行結果


1

にゃこ

1

にゃこ

にゃこ

ンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンン。}・・ネ|


ソーラー「クラスSuutitoMojiのメンバ関数であるoperator=の


定義を改良することにより


クラスSuutitoMoji型のオブジェクトに違うクラスSuutitoMoji型のオブジェクトを代入する場合だけでなく


クラスSuutitoMoji型のオブジェクトに同じクラスSuutitoMoji型のオブジェクトを代入する


つまり


クラスSuutitoMoji型のオブジェクトaにクラスSuutitoMoji型のオブジェクトaを代入する


a=a;


を実行するような場合にも


警告文が表示されることなく


プログラムが


無事に実行することができるようになりましたね


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

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


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

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


が実行されていますが


a=a


つまり


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


a.operator=(a)



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


を表すことになっているので



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

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


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

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



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

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


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

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


を表すことになります


ですので


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

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


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

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


が実行されると


コマンドプロンプト画面に


1

にゃこ

1

にゃこ


が表示されることになります


そして


delete a.i;


が実行されると


a.iは消去されませんが


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


つまり


a.iによって動的に確保されたメモリ領域が解放されて


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


は消去されます


a.iによって動的に確保されたメモリ領域は解放されて


何も文字列データが格納されていない状態になります


このとき


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


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


が実行されると


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


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


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

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


ンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンン。}・・ネ|


が表示されることになります」

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

作者を応援しよう!

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

応援したユーザー

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

新規登録で充実の読書を

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

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

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