代入演算子=のオーバーロードを実行してみます その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型のオブジェクト
が実行されているので
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;
を実行しているのにな・・・」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます