オブジェクトaをオブジェクトbで初期化しても必ずオブジェクトaのメンバ変数とオブジェクトbのメンバ変数の独立性は保たれます

つづきで~す


ソーラー「


SuutitoMoji a = b;


を実行したとき


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



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


の独立性は保たれる


つまり


クラスSuutitoMoji型のオブジェクトaに格納されているデータが変更されても


クラスSuutitoMoji型のオブジェクトbに格納されているデータは変更されないし


クラスSuutitoMoji型のオブジェクトbに格納されているデータが変更されても


クラスSuutitoMoji型のオブジェクトaに格納されているデータは変更されません」



マックス「それはそうだろう。普通過ぎるだろうぉぉ」


ソーラー「えへへ そう思いますか😊


私もそう思います


でも


私は


さんざん勘違いしていました( ^ω^)・・・


いやあ やっちまったなぁ~


さて


次のような


クラスSuutitoMojiがあるとします。


クラスSuutitoMojiのクラス宣言は次のようになっているとします」

👇


class SuutitoMoji{


public:


int x;


public:


char* i;


};


ソーラー「


もし


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


SuutitoMoji b;


を実行したなら


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


b.x

b.i


が作製されますが


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


b.x



int型の変数



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


b.i



char*型のポインタ変数となっています


ということは


char*型のポインタ変数


b.i



char*型のポインタ変数なので


char型の変数のアドレスを格納することができます


ということは


new char[50];


を実行して動的に


連続したchar型の配列変数50個分のメモリ(50バイト分)を確保した場合


b.i=new char[50];


を実行することにより



連続したchar型の配列変数50個分のメモリ(50バイト分)の


先頭のメモリのアドレスを



char*型のポインタ変数であるオブジェクトbのメンバ変数


b.i


に格納することができます


このとき


strcpy関数(どの統合開発環境でもおつかいいただけます)



strcpy_s関数(Visual Studioをお使いの方のみおつかいいただけます)



用いて


b.i=new char[50];(動的にメモリを確保しています)


を実行して


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iに格納されることになったアドレス番号


のついたメモリを先頭とするメモリ領域に


文字列データを


格納してみたいと思います」


マックス「はぁ? strcpy関数? わっかりにくいぞ」


ソーラー「そっか・・・


では😊


もうちょっと簡潔にして


strcpy関数(どの統合開発環境でもおつかいいただけます)



strcpy_s関数(Visual Studioをお使いの方のみおつかいいただけます)



用いて


動的に確保したメモリに


文字列データを


格納してみたいと思います



どうかな?」


マックス「いいなあ これ、この説明なんだよ



strcpy関数ってなんのことだったか~忘れちまったぜぃ😊」




註)


Visual Studioをお使いの方は


strcpy関数をお使いになる場合は


プログラムの先頭に


#pragma warning(disable: 4996)


を記述してください


strcpy関数を用いれば


strcpy(b.i, "ねこねこ");


を実行して


文字列データ


"ねこねこ"



char*型のポインタ変数であるクラスSuutitoMoji型のオブジェクトbのメンバ変数


b.i


が格納しているアドレス番号の付いたメモリを先頭とする連続したメモリ領域に


格納することができます


つまり


文字列データ


"ねこねこ"



b.i=new char[50];


を実行して


動的に確保したメモリに格納することができます




Visual Studioをお使いの方は


プログラムの先頭に


#pragma warning(disable: 4996)


を記述しなくても


strcpy_s関数を用いて


strcpy_s(b.i, 50,"ねこねこ");


を実行して


文字列データ


"ねこねこ"



char*型のポインタ変数であるオブジェクトbのメンバ変数


b.i


が格納しているアドレス番号の付いたメモリに格納することができます



つまり


文字列データ


"ねこねこ"



b.i=new char[50];


を実行して


動的に確保したメモリに格納することができます



と💖こ💖ろ💖で💖😊



strcpy_s関数を用いる場合は


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


b.i


が格納しているアドレス番号を先頭とする動的に確保した連続したメモリ領域に


何バイト分までのデータを格納することができるかを指定する必要があります


そうですね


strcpy_s(b.i, 50,"ねこねこ");


のように


第2引数に50のように数値を記述する必要があります


この場合は


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


b.i


が格納しているアドレス番号を先頭とする連続した動的に確保したメモリ領域に


50バイト分までのデータを格納することができます


第2引数を記述せずに


strcpy_s(b.i, "ねこねこ");


を実行しようとすると


ビルドエラーが表示されます


では


文字列データ


"ねこねこ"



char*型のポインタ変数であるクラスSuutitoMoji型のオブジェクトbのメンバ変数


b.i


が格納しているアドレス番号を先頭とする連続した動的に確保したメモリ領域に


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


もっと簡単にいいかえてみます


strcpy_s関数は


あるメモリ領域に格納されている文字列データを


別のメモリ領域にコピーする機能があります


strcpy_s(b.i, 50,"ねこねこ");


(この場合 文字列データ"ねこねこ"はあるメモリ領域に格納されています)


を実行することにより


文字列データ


"ねこねこ"



(b.i = new char[50];


を実行して)


動的に確保したメモリに

(char*型のポインタ変数であるb.iには動的に確保したメモリ領域の先頭のメモリのアドレスが格納されています)

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


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


👇


#pragma warning(disable: 4996)


#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(b.i, "ねこねこ");


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

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

return 0;

}


プログラムの実行結果


1

ねこねこ



Visual Studioをお使いの方はこちらのプログラムも実行できます

👇


#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, "ねこねこ");//strcpy_s関数をもちいています


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

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


return 0;

}


プログラムの実行結果


1

ねこねこ



ソーラー「


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


の実行により


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


ねこねこ


が表示されています


b.i = new char[50];


によって


動的に確保したメモリに


文字列データ


"ねこねこ"


を格納することができました


strcpy_s(b.i, 50, "ねこねこ");



オブジェクトbのメンバ変数b.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に


文字列データを格納しているのですね」



マックス「ふむふむう  いい説明だな・・・」


ソーラー「そうです? えへへ


ここで


SuutitoMoji b;


によって作製された


クラスSuutitoMoji型のオブジェクトbを用いて


aのオブジェクト宣言、初期化


SuutitoMoji a = b;


を実行してみたいと思います


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

👇


#pragma warning(disable: 4996)


#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(b.i, "ねこねこ");



SuutitoMoji a = b;


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

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

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

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


return 0;

}


プログラムの実行結果


1

ねこねこ

1

ねこねこ


Visual Studioをお使いの方はこちらも実行できます


👇

#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;


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

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

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

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


return 0;

}


プログラムの実行結果


1

ねこねこ

1

ねこねこ


ソーラー「このプログラムの最大の注目ポイントは



strcpy_s(b.i, 50, "ねこねこ");


を実行した後


SuutitoMoji a = b;


の実行により


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


a.x

a.i


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


b.x

b.i


を代入することにより


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


a.x


には


数値データ1



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


a.i

には


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


格納されているという点です


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


付いたメモリを先頭とするメモリ領域には


文字列データ


"ねこねこ"


が格納されています


マックス「


文字列データ


"ねこねこ"



b.i = new char[50];


の実行により


動的に確保したメモリに格納されているんだろう


(このとき


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



ソーラー「そうなんです


SuutitoMoji a = b;


の実行により


a.i=b.i;


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


b.i = new char[50];


の実行により


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


b.i


に格納された


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


先頭のメモリのアドレスは


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


a.i


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


b.i


の両方に格納されていることになります




              このとき


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


              🌹a.i🌹


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


              🌷b.i🌷


のどちらにstrcpy_s関数を作用させても


動的に確保したメモリに


文字列データを格納することができます


なぜなら


ポインタ変数であるオブジェクトaのメンバ変数a.iに格納されたアドレス



ポインタ変数であるオブジェクトbのメンバ変数b.iに格納されたアドレス


はともに


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


を格納しており


strcpy(a.i, "ねこねこ");

strcpy(b.i, "ねこねこ");


が実行されると


ともに


動的に確保したメモリに


文字列データ"ねこねこ"は格納されることになるからです



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

👇



#pragma warning(disable: 4996)


#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(b.i, "ねこねこ");



SuutitoMoji a = b;


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

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

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

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



a.x = 2;

strcpy(b.i, "ねこねこねこ");


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

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

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

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


a.x = 3;

strcpy(a.i, "ネコネコにゃんこ");


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

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

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

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



return 0;

}


プログラムの実行結果


1

ねこねこ

1

ねこねこ

1

ねこねこねこ

2

ねこねこねこ

1

ネコネコにゃんこ

3

ネコネコにゃんこ


Visual Studioをお使いの場合はこちらのプログラムも実行できます

👇


#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;


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

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

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

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



a.x = 2;

strcpy_s(b.i, 50, "ねこねこねこ");


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

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

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

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


a.x = 3;

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


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

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

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

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



return 0;

}


プログラムの実行結果


1

ねこねこ

1

ねこねこ

1

ねこねこねこ

2

ねこねこねこ

1

ネコネコにゃんこ

3

ネコネコにゃんこ


ソーラー「


このプログラムでは


まず


SuutitoMoji b;


b.x = 1;


b.i = new char[50];


strcpy_s(b.i, 50, "ねこねこ");


の実行により


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


数値データ1



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


文字列データ


"ねこねこ"


を格納しているメモリの先頭のアドレスが格納されます


そして


SuutitoMoji a = b;


が実行されると


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


には


数値データ1



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


文字列データ


"ねこねこ"


を格納している動的に確保したメモリ領域の先頭のメモリのアドレスが格納されます


もちろん


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


数値データ1



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


文字列データ


"ねこねこ"


を格納している動的に確保したメモリ領域の先頭のメモリのアドレスが


保存されたままですね




             さあいよいよです


このプログラムの


a.x = 2;

strcpy_s(b.i, 50, "ねこねこねこ");


に御注目ください


a.x = 2;


が実行されると


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.xに格納されている数値データは


1から2に変化しますが


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.xに格納されている数値データは


1のまま変化しないことが


後に続く命令文


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

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

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

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


の実行結果が


1

ねこねこねこ

2

ねこねこねこ


となっていることからわかります


マックス「そんなの あたりまえなのでないか?」



ソーラー「ふふっ


そうなんです


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



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



それぞれ独立したメモリを管理しているからなんです



 さて       


b.iには動的に確保したメモリ領域の先頭のメモリのアドレスが格納されています



次は


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


新たに


文字列データ


"ねこねこねこ"



つまり


b.iを用いて動的に確保したメモリに


文字列データ

"ねこねこねこ"


を格納する命令文


strcpy_s(b.i, 50, "ねこねこねこ");


が実行されていますね


その解説です


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


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


"ねこねこ"

から

"ねこねこねこ"


に変化しますが


つまり


動的に確保されているメモリに格納されている文字列データは


"ねこねこ"

から

"ねこねこねこ"


に変化しますが


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


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


"ねこねこ"

から

"ねこねこねこ"


に変化します


そのことが


後に続く命令文


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

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

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

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


の実行結果が


1

ねこねこねこ

2

ねこねこねこ


となっていることからわかります


なぜなら


SuutitoMoji a = b;


の実行により


a.i=b.i


が実行されているので


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



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


同じアドレス番号になっているからです


まさに


a.i=b.i



というわけです             


ですので


b.iを用いて


strcpy_s(b.i, 50, "ねこねこねこ");


を実行して


オブジェクトbのメンバ変数b.iが格納しているアドレス番号の付いたメモリを先頭とするメモリ領域に


文字列データ"ねこねこねこ"


を格納するということは




a.iを用いて


strcpy_s(a.i, 50, "ねこねこねこ");


を実行して


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


文字列データ"ねこねこねこ"


を格納することと等しいというわけです



strcpy_s(a.i, 50, "ねこねこねこ");


もしくは


strcpy_s(b.i, 50, "ねこねこねこ");


のどちらを実行しても


同じメモリ領域に


文字列データ"ねこねこねこ"は格納されることになるのですね


もちろん


そのメモリ領域の先頭のメモリのアドレスは


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iに格納されていますし


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iにも格納されています


今のプログラムの


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

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

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

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


の実行結果が


1

ねこねこねこ

2

ねこねこねこ


になっています


この

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

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

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

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


の中の


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

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


の実行結果に御注目下さい


命令文


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


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


格納されている文字列データを表示する命令文であり



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



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


格納されている文字列データを表示する命令文ですね


そして


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iに格納されているアドレス番号



クラスSuutitoMoji型のオブジェクトaのメンバ変数a.iに格納されているアドレス番号


は等しいので


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

cout << a.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(b.i, "ねこねこねこ");


が実行されると


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

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


の実行結果は


ともに


ねこねこねこ


になるので


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



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




     (^_^)v同じメモリを管理しているのでは?(#^^#)




と思われる方もおられるかもしれませんが


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



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


の独立性は保たれています


つまり


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



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


の管理しているメモリは異なっています


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



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


の管理しているメモリに同じアドレスが代入されているだけです


だから


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

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


の実行結果は


ともに


ねこねこねこ


になるのです」



マックス「


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



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



の独立性は保たれている・・・か・・・


まあそ~だよな」


ソーラー「


さらに次に続く命令文


a.x = 3;

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


に御注目下さい




a.x = 3;


が実行されると


クラスSuutitoMoji型のオブジェクトaのメンバ変数a.xに格納されている数値データは


2から3に変化しますが


クラスSuutitoMoji型のオブジェクトbのメンバ変数b.xに格納されている数値データは


1のまま変化しないことが


次に続く命令文


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

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

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

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


の実行結果が


1

ネコネコにゃんこ

3

ネコネコにゃんこ


となっていることからわかります


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



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



それぞれ独立したメモリを管理しているからですね


そして


今度は



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


文字列データ

"ネコネコにゃんこ"


を格納する命令文


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


が実行ですね


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


が実行されると



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


格納される文字列データは


"ねこねこねこ"

から

"ネコネコにゃんこ”


に変化しますが


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


格納される文字列データも


"ねこねこねこ"

から

"ネコネコにゃんこ”


に変化することになります


なぜなら


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



クラスSuutitoMoji型のオブジェクトbのメンバ変数b.iに格納されているアドレス



          💖同じアドレス💖



であり



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



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




同一のメモリ領域だからです




そのことが


後に続く命令文


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

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

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

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


の実行結果が


1

ネコネコにゃんこ

3

ネコネコにゃんこ


となっていることからわかります



もちろん


この場合も


オブジェクトaのメンバ変数a.i



オブジェクトbのメンバ変数b.i


は独立しています」



マックス「なんか 不思議な感じがするな・・・」

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

作者を応援しよう!

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

応援したユーザー

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

新規登録で充実の読書を

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

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

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