🌻天国にいけるC++言語入門🌻 進化し続けるオブジェクト指向プログラミング ver3.2307
代入演算子=のオーバーロードを実行する その2 クラスのメンバ関数operator=の定義を改良してみます
代入演算子=のオーバーロードを実行する その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のメンバ関数である
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のメンバ関数
が実行される
このとき
thisはクラスSuutitoMoji型のオブジェクト
そして
ここでの
注目ポイントは
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.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の格納しているアドレスのメモリを先頭とするメモリ領域に格納されている文字列データ
ンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンンン。}・・ネ|
が表示されることになります」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます