🌻天国にいけるC++言語入門🌻 進化し続けるオブジェクト指向プログラミング ver3.2307
a.i=b.iであればstrcpy_s(a.i,50,"ねこねこ");、strcpy_s(b.i,50,"ねこねこ");は同じアドレスのメモリに"ねこねこ"を格納することになります
a.i=b.iであればstrcpy_s(a.i,50,"ねこねこ");、strcpy_s(b.i,50,"ねこねこ");は同じアドレスのメモリに"ねこねこ"を格納することになります
ソーラー「では
今まで登場した
問題点を整理すると・・・」
マックス「何も問題点なんてないんじゃないか?」
ソーラー「大正解です
何も問題なんて~ぇ😊ないんです」
てんC「今までのお話は
とても単純で
オブジェクト宣言により生成される
オブジェクトaとオブジェクトb
の独立性は保たれる
つまり
オブジェクト宣言により生成される
オブジェクトaとオブジェクトb
は
それぞれ別のメモリを管理する
というお話でしたね😊」
マックス「??
なぜ
ここで
オブジェクト宣言により生成される
オブジェクトaとオブジェクトb
は
それぞれ別のメモリを管理する
という基本的な話になってくるんだ?
あたりまえすぎないか?
オブジェクトaとオブジェクトb
は
それぞれ別のメモリを管理するということに
何も問題はないじゃないか」
🌞 🌞 🌞 🌞 🌞 🌞 🌞
さて
クラスSuutitoMojiがあるとします。
クラスSuutitoMojiのクラス宣言は次のように設定されているとします」
👇
class SuutitoMoji{
public:
int x;
public:
char* i;
};
🌞 🌞 🌞 🌞 🌞 🌞 🌞
ソーラー「この
クラスSuutitoMojiを用いて
bのクラスSuutitoMoji型のオブジェクト宣言
SuutitoMoji b;
を
実行して
クラスSuutitoMoji型のオブジェクトbを生成したとします
その次に
aのクラスSuutitoMoji型のオブジェクト宣言、
クラスSuutitoMoji型のオブジェクトbによる初期化
SuutitoMoji a=b;
を実行すれば
クラスSuutitoMoji型のオブジェクトbのメンバ変数
b.x
b.i
が
格納しているデータを
クラスSuutitoMoji型のオブジェクトaのメンバ変数
a.x
a.i
に代入して
クラスSuutitoMoji型のオブジェクトaを初期化することができます 」
てんC「
SuutitoMoji a=b;
が実行されると
普通に
クラスSuutitoMoji型のオブジェクトa
が
クラスSuutitoMoji型のオブジェクトb
によって初期化されますね😊
SuutitoMoji a=b;
を
実行しても
もちろん
💖クラスSuutitoMoji型のオブジェクトaはクラスSuutitoMoji型のオブジェクトbそのものをあらわすようになるわけではなく💖
クラスSuutitoMoji型のオブジェクトaとクラスSuutitoMoji型のオブジェクトbの独立性は保たれていて
クラスSuutitoMoji型のオブジェクトaとクラスSuutitoMoji型のオブジェクトbは
それぞれ独立したメモリを管理しています
つまり
クラスSuutitoMoji型のオブジェクトaのメンバ変数
a.x
a.i
と
クラスSuutitoMoji型のオブジェクトbのメンバ変数
b.x
b.i
の
独立性は保たれているので
クラスSuutitoMoji型のオブジェクトaのメンバ変数
a.x
a.i
に格納されているデータを変更しても
クラスSuutitoMoji型のオブジェクトbのメンバ変数
b.x
b.i
に格納されているデータは変更されないのですね😊」
ソーラー「そう
これが
aのクラスSuutitoMoji型のオブジェクト宣言、初期化
SuutitoMoji a=b;
を実行したときの
クラスSuutitoMoji型のオブジェクトa
と
クラスSuutitoMoji型のオブジェクトbの状態です
そう
SuutitoMoji a=b;
が実行されても
💖💖🌞必ず🌞💖
クラスSuutitoMoji型のオブジェクトa
と
クラスSuutitoMoji型のオブジェクトb
は
それぞれ独立したメモリを管理することになります」
ソーラー「さて
このクラスSuutitoMojiのように
クラスSuutitoMojiのメンバ関数宣言に
🍅char*型のポインタ変数宣言🍅
🍅char* i;🍅
が設定されている場合に
bのクラスSuutitoMoji型のオブジェクト宣言
SuutitoMoji b;
を
実行し
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.x
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
を生成したとします
b.xには
b.x=1;
を実行して
数値データ1を代入し
b.iには
(b.i=new char[50];
を実行して
動的にメモリ領域を確保し)
動的に確保したメモリ領域の先頭のメモリを格納します
初期化の完了ですね
次に
strcpy_s(b.i,50,"にゃこ");
を実行して
動的に確保したメモリ領域に
文字列データ
"にゃこ"
を格納したとします
さらに
クラスSuutitoMoji型のオブジェクトa
を生成し
クラスSuutitoMoji型のオブジェクトbで
初期化する命令文
SuutitoMoji a = b;
を実行したとします
この場合でも
クラスSuutitoMoji型のオブジェクトa
と
クラスSuutitoMoji型のオブジェクトb
の独立性は保たれます
すなわち
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.x
と
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.x
は独立性が保たれ
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.x
と
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.x
は
それぞれ別のメモリを管理します
さらに
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
と
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
も独立性が保たれ
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
と
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
は
それぞれ別のメモリを管理することになります
このとき
SuutitoMoji a = b;
が実行されているので
a.i=b.i
が実行されていますね
a.i=b.iにより
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
と
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
は
ともに
💖同じアドレス💖
を格納することになります
b.iには
クラスSuutitoMoji型のオブジェクトbのメンバ変数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
は
ともに
同じ
文字列データ"にゃこ"
を格納しているメモリ領域の先頭のメモリのアドレス
を格納することになります
このとき
strcpy_s関数を用いて
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に宛てて
つまり
(文字列データ"にゃこ"を格納している)動的に確保したメモリ領域に宛てて
文字列データ"ねこねこ"
を
格納してみたいと思います
動的に確保したメモリ領域に
格納されている文字列データ
"にゃこ"
の代わりに
"ねこねこ"
を
格納したいというわけです
そのときの命令文は
strcpy_s(a.i,50,"ねこねこ");
となります
strcpy_s(a.i,50,"ねこねこ");
が実行されても
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号
つまり
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納している動的に確保したメモリ領域の先頭のメモリのアドレス番号
は
そのまま
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
に格納されたままで
変更されることはありません」
マックス「はいぃ? それはそうだろぉ
strcpy_s(a.i,50,"ねこねこ");
は
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域(動的に確保したメモリ領域)に
つまりイコール
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iを用いて動的に確保したメモリ領域に
文字列データ"ねこねこ"
を
格納する命令文だろう?
strcpy_s関数は
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号を
変更する命令文じゃないだろう
ふはははは
動的に確保したメモリ領域に
文字列データ"ねこねこ"
が格納されるときに
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号が
変更されるっていうのはありえないな」
ソーラー「もちろんその通りなんです
そして
SuutitoMoji a = b;
が実行されることにより
a.i=b.i
が実行されているので
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
と
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
は
ともに同じアドレス番号
すなわち
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iを用いて
動的に確保したメモリ領域の先頭のメモリのアドレス番号
を格納することになります
つまり
strcpy_s(a.i,50,"ねこねこ");
が実行されると
動的に確保したメモリ領域に
文字列データ"ねこねこ"
が格納されることになるのですが
a.i
b.i
ともに動的に確保したメモリのアドレスを格納しているので
cout<<a.i<<"\n";
を実行しても
cout<<b.i<<"\n";
を実行しても
コマンドプロンプト画面に
文字列データ"ねこねこ"
が表示されることになります
なぜなら
cout<<a.i<<"\n";
は
a.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に格納されている文字列データを
コマンドプロンプト画面に表示する命令文で
cout<<b.i<<"\n";
は
b.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に格納されている文字列データを
コマンドプロンプト画面に表示する命令文で
a.iが格納しているアドレス番号
と
b.iが格納しているアドレス番号
は
ともに同じ
動的に確保したメモリのアドレス番号だからですね
さらに次に
クラスSuutitoMoji型のオブジェクトのメンバ変数b.iに宛てて
strcpy_s関数を用いた
strcpy_s(b.i,50,"にゃん");
が実行されると
動的に確保されたメモリ領域には
文字列データ
"にゃん"
が
格納されることになるのですが
a.i
b.i
ともに動的に確保したメモリ領域の先頭のメモリのアドレスを格納しているので
cout<<a.i<<"\n";
を実行しても
cout<<b.i<<"\n";
を実行しても
コマンドプロンプト画面に
文字列データ"にゃん"
が表示されることになります
このように
a.i
b.i
ともに動的に確保したメモリ領域の先頭のメモリのアドレスを格納しているので
a.iやb.iを用いて
strcpy_sを使って文字列データを動的に確保したメモリに格納した場合
cout<<a.i<<"\n";
cout<<b.i<<"\n";
の実行結果は
必ず同じ動的に確保したメモリに格納された文字列が表示されることになるわけです
もちろん
この場合でも
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
と
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
の
独立性は
保たれています
つまり
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
に格納されているをアドレスを変更しても
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
に格納されているアドレスは変更されないし
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
に格納されているアドレスを変更しても
クラスSuutitoMoji型のオブジェクトbのメンバ変数a.i
に格納されているアドレスは変更されません
めでたし めでたし
ちゃんこ、ちゃんこ
というわけです
ですが
strcpy_s(a.i,50,"ねこねこ");
が実行されると
cout<<a.i<<"\n";
cout<<b.i<<"\n";
の実行結果が
ねこねこ
ねこねこ
strcpy_s(b.i,50,"にゃん");
が実行されると
cout<<a.i<<"\n";
cout<<b.i<<"\n";
の実行結果が
にゃん
にゃん
となると
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
と
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
は同じメモリにアクセスしているように見え
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.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,"ねこねこ");
が実行されるだけで
cout<<a.i<<"\n";
cout<<b.i<<"\n";
の実行結果が
ともに同時に
等しく
ねこねこ
が表示されるように
変化してしまうからなんだね 」
おまけ
cout<<a.i<<"\n";
cout<<b.i<<"\n";
は
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
に格納されているアドレスを表示する命令文でなく
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
に格納されているアドレス番号のついたメモリを先頭とするメモリ領域に格納されている文字列データ
を
表示する命令文なんです
間違えやすいところです
solarplexussより
ですから
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
に格納されているアドレスが
ともに同じ動的に確保されたメモリ領域のアドレスなら
動的に確保されたメモリ領域に格納される文字列データが
strcpy_s関数によって
変更されると
そのたびに
cout<<a.i<<"\n";
cout<<b.i<<"\n";
の実行結果も
一緒に
その動的に確保されたメモリ領域に格納された文字列データに
変更されるというわけです
そう
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
に格納されているアドレスがともに
同じ動的に確保されたメモリ領域の先頭のメモリのアドレスなので
動的に確保されたメモリ領域に格納されている文字列データが変更されると
cout<<a.i<<"\n";
cout<<b.i<<"\n";
の実行結果も
一緒に
その動的に確保されたメモリ領域に格納された文字列データに
変更されるのですね
strcpy_s(a.i,50,"ねこねこ");
は
動的に確保されたメモリ領域に文字列データ
"ねこねこ”
を新たに格納する命令文です
ですから
strcpy_s(a.i,50,"ねこねこ");
が実行されて
動的に確保されたメモリ領域に
文字列データ
"ねこねこ”
が格納されることになると
cout<<a.i<<"\n";
cout<<b.i<<"\n";
の実行結果も同時に
ねこねこ
ねこねこ
になるというわけです」
ソーラー「はあ、はあ」
ソーラー「
ここで
今までの流れをあらわすプログラムを実行してみたいと思います
そのプログラムは次のようになります
👇
#include <iostream>
using namespace std;
class SuutitoMoji{
public:
int x;
public:
char* i;
};
int main() {
SuutitoMoji b;
b.x = 1;
b.i = new char[50];
strcpy_s(b.i,50, "にゃこ");
SuutitoMoji a = b;
strcpy_s(a.i, 50, "ねこねこ");
cout << a.i << "\n";
cout << b.i << "\n";
strcpy_s(b.i, 50, "にゃん");
cout << a.i << "\n";
cout << b.i << "\n";
return 0;
}
プログラムの実行結果
ねこねこ
ねこねこ
にゃん
にゃん
ソーラー「このプログラムでは
SuutitoMoji b;
b.x = 1;
により
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.xに1が代入されています
そして
b.i = new char[50];
を実行することにより
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iを用いて
動的にメモリ領域を確保しています
このとき
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iには動的に確保したメモリ領域の先頭のメモリのアドレスが
代入されることになります
次に
strcpy_s(b.i,50, "にゃこ");
が実行されると
動的に確保されたメモリ領域に
文字列データ
"にゃこ"
が格納されることになります
この状態で
SuutitoMoji a = b;
が実行されると
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.xには
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.xの格納している
数値データ1が
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iには
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iの格納している
(動的に確保されたメモリ領域の先頭のメモリの)アドレスが
格納されることになります
この状態で
strcpy_s(a.i, 50, "ねこねこ");
が実行されると
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iの格納しているアドレス番号の付いたメモリを先頭とするメモリ領域にあてて
つまり
動的に確保したメモリ領域に
文字列データ
"ねこねこ"
は格納されることになります
cout << a.i << "\n";
は
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域
に格納されている文字列データを
コマンドプロンプト画面に表示する命令文
で
cout << b.i << "\n";
は
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に
格納されている文字列データを
コマンドプロンプト画面に表示する命令文です
SuutitoMoji b;
b.x = 1;
b.i = new char[50];
strcpy_s(b.i,50, "にゃこ");
のあと
SuutitoMoji a = b;
が実行されて
a.i=b.i
となっているので
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.i
と
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.i
は
ともに動的に確保したメモリ領域の先頭のメモリのアドレスを格納することになり
cout << a.i << "\n";
と
cout << b.i << "\n";
は
等しく動的に確保されたメモリ領域に格納されている文字列データを
コマンドプロンプト画面に表示する命令文となります
cout << a.i << "\n";
が実行されると
クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に格納された文字列データ
つまり
動的に確保されたメモリ領域に格納された文字列データ
"ねこねこ”
がコマンドプロンプト画面に表示され
cout << b.i << "\n";
が実行されると
クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iが格納しているアドレスの付いたメモリを先頭とするメモリ領域
つまり
動的に確保されたメモリ領域
に格納された文字列データ
"ねこねこ”
がコマンドプロンプト画面に表示されることになります
同様に
次に
strcpy_s(b.i, 50, "にゃん");
が実行されると
cout << a.i << "\n";
cout << b.i << "\n";
の
実行結果は
にゃん
にゃん
になります
めでたし
めでたし
マックス「やったな ソーラー
あたりまえのこと~のような気がするが。。。
なんか よくわからんような気もするな
だが この解説の詳しさには驚いたぞ!」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます