C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

参照型、値型について

[トピック内 13 記事 (1 - 13 表示)]  << 0 >>

■100837 / inTopicNo.1)  参照型、値型について
  
□投稿者/ しーや (11回)-(2022/11/01(Tue) 18:34:10)

分類:[C#] 

2022/11/01(Tue) 22:07:57 編集(投稿者)
2022/11/01(Tue) 22:07:52 編集(投稿者)

Other classA = new Other();
Other classB = new Other();
classA.Value = 10;
classB.Value = 20;

classA = classB;
classB.Value = 30;

MessageBox.Show(classA.Value.ToString());
MessageBox.Show(classA.Value.ToString());


上記コードでの classA = classB のように、変数同士をイコールで結ぶ必要ってなんでしょうか。
参照渡しの性質(片方に代入するともう片方も連動する)を利用するためですか?
それとも(場合によっては)別の意図も含まれているのですか?

うまく日本語にできておらずすいません。
わからないところがあったら「ここはこういう意味?」みたいに指摘していただけると、訂正補足がしやすいです。
引用返信 編集キー/
■100838 / inTopicNo.2)  Re[1]: 参照渡し、値渡しについて
□投稿者/ 魔界の仮面弁士 (3483回)-(2022/11/01(Tue) 19:07:55)
2022/11/01(Tue) 19:42:46 編集(投稿者)

No100837 (しーや さん) に返信
> 変数同士をイコールで結ぶ必要ってなんでしょうか。
「a = b;」は、b の内容を a に代入する行為です。

「var c = d;」は変数 c を宣言し、
その初期値として変数 d の値を与えます。

この時、変数のデータ型は何でも構いません。値型でも参照型でも。


> Other classA = new Other();
Other クラスを new で実体化させて、
その実体化させたインスタンスを classA に代入している。
(classA は、Other1 のインスタンスを参照している状態)


> Other classB = new Other();
Other クラスを new でもう一つ実体化させて、以下同文。
classB は、Other2 のインスタンスを参照している状態。


> classA.Value = 10;
> classB.Value = 20;
変数 classA / classB を通じて、
Other1 / Other2 インスタンスの Value プロパティを書き換え。


> classA = classB;
classA は Other1 を参照していたという過去は忘れて、
新たに Other2 を参照している状態になりました。

Other2インスタンスは、classA と classB の両方から参照されている状態です。

ただしそれは、Other の型が参照型(たとえば class)だった場合の話。
Other が値型(たとえば struct)だった場合には、
classA にセットされるのは Other2 インスタンスへの参照ではなく、
Other2 の値をコピーしたものがセットされます。


> classB.Value = 30;
もしも Other が参照型だった場合、
classA.Value は 30 となります。

もしも Other が値型だった場合、
classA.Value は 10 のままです。


> MessageBox.Show(classA.Value.ToString());
> MessageBox.Show(classA.Value.ToString());
これ、同じ行が 2 回書かれてますけど、それで良いんですか?


っていうかこれ、参照渡し/値渡しとは何の関係も無いですよね。
もしかして、参照型/値型の話と混ざっていませんか?

「参照渡し」とか「参照型」とか「参照ローカル変数」とか、
似たような用語があるので、混同されぬようご注意あれ。
引用返信 編集キー/
■100839 / inTopicNo.3)  Re[1]: 参照渡し、値渡しについて
□投稿者/ WebSurfer (2583回)-(2022/11/01(Tue) 21:13:59)
No100837 (しーや さん) に返信

> 参照渡し、値渡しについて

VB.NET のメソッドの引数の値渡し (ByVal) / 参照渡し (ByRef) の話とは違うのですかね?

違うようですが、もしその話なら以下の記事を見てください。

VB.NET の ByVal / ByRef と値型 / 参照型
http://surferonwww.info/BlogEngine/post/2019/01/20/byval-byref-and-value-type-reference-type-in-vbnet.aspx

引用返信 編集キー/
■100840 / inTopicNo.4)  Re[2]: 参照渡し、値渡しについて
□投稿者/ しーや (12回)-(2022/11/01(Tue) 22:04:17)
>>classA = classB;
> classA は Other1 を参照していたという過去は忘れて、
> 新たに Other2 を参照している状態になりました。
>
> Other2インスタンスは、classA と classB の両方から参照されている状態です。
Other2はOtherクラスで、Other1は無くなった。いう考え方は正しいですか?

> ただしそれは、Other の型が参照型(たとえば class)だった場合の話。
> Other が値型(たとえば struct)だった場合には、
> classA にセットされるのは Other2 インスタンスへの参照ではなく、
> Other2 の値をコピーしたものがセットされます。
例外の解説助かります。

> これ、同じ行が 2 回書かれてますけど、それで良いんですか?
コードは解説記事から引っ張ってきたので真意はわからないですけど、多分片方はclassBですね。

> っていうかこれ、参照渡し/値渡しとは何の関係も無いですよね。
> もしかして、参照型/値型の話と混ざっていませんか?
>
> 「参照渡し」とか「参照型」とか「参照ローカル変数」とか、
> 似たような用語があるので、混同されぬようご注意あれ。
まんまと引っかかってました。
すいません。
引用返信 編集キー/
■100841 / inTopicNo.5)  Re[2]: 参照渡し、値渡しについて
□投稿者/ しーや (13回)-(2022/11/01(Tue) 22:07:30)
> VB.NET のメソッドの引数の値渡し (ByVal) / 参照渡し (ByRef) の話とは違うのですかね?

c#でvisual studioを使ってるので、多分違います。
VB.NETという概念をいま初めて知りましたし。
わざわざお手数おかけしてすいません。
引用返信 編集キー/
■100842 / inTopicNo.6)  Re[3]: 参照渡し、値渡しについて
□投稿者/ 魔界の仮面弁士 (3484回)-(2022/11/01(Tue) 23:02:03)
No100840 (しーや さん) に返信
>>Other2インスタンスは、classA と classB の両方から参照されている状態です。
「クラス」と「インスタンス」の違いは分かりますか?


> Other2はOtherクラスで、Other1は無くなった。いう考え方は正しいですか?
無くなったと言えなくも無いですが、Other が struct ではなく class なのであれば、
「どの変数からも参照されていない状態になった」という状況が近いです。

参照されなくなったからと言って、その時点で直ちに消えるわけではありません。
この時点では、誰にも利用されない未使用状態のまま、メモリ上に残った状態となります。
ただ、そういった未使用のインスタンスは、その後、自動的に処分されて
消失する仕組みになっていますので、結果的には無くなったと言うこともできるかと。


---

int a = 1;
a = 2;
この場合、a は 1 という情報を忘れて、2 という情報値を保持している状態になりました。


int a = 1;
int b = 2;
a = b;
この場合も、a が保持していた 1 という情報は失われ、a は 2 という情報値を保持している状態に変化します。


Other classA = new Other(1);
Other classB = new Other(2);
classA = classB;
この場合、classA は Other1 という情報を忘れて、Other2 という情報を保持している状態になりました。
ここまでは、値型でも参照型でも大差ありません。

問題はそのあと、
 classA.Value = 99;
のように、そのメンバーを書き換えた場合の振る舞いです。


Other が struct(値型) であった場合は、「classA = classB;」というのは
値データそのものをコピーする動作となります。
コピーされた別のデータの Value メンバーを書き換えても、
コピー元となった classB の Value は変化しません。

一方、Other が class(参照型) であった場合は、「classA = classB;」というのは
インスタンスのコピーではなく、そのインスタンスの「参照情報」をコピーする動作となります。
参照がコピーされたとしても、同じ実体(インスタンス)を複数の変数から参照しているだけなので、
classA.Value を書き換えると、同じ実体の情報を見ている classB.Value も連動して変化します。


>>ただしそれは、Other の型が参照型(たとえば class)だった場合の話。
>>Other が値型(たとえば struct)だった場合には、
>>classA にセットされるのは Other2 インスタンスへの参照ではなく、
>>Other2 の値をコピーしたものがセットされます。
> 例外の解説助かります。

たとえば「配列」は「参照型」なので、こういう動きをします。

int[] ary1 = { 11, 22, 33, 44 }; // 4 つの要素を持った配列を 1 つ作る
int[] ary2 = ary1; // その配列を 変数 ary2 からも参照できる状態にする(参照情報がコピーされただけで、参照先の実体は複製されていない)
ary1[0] = 9; // ary1 の先頭要素を 11 から 9 に変更する
int result = ary2[0]; // ary2[0] も 9 に変化している。(ary1 と ary2 は、同じ配列を参照している)
// この場合、配列の実体は最初に作った 1 つしかなく、それを ary1 と ary2 から参照している状態。

-----

参照型をコピーする場合は、複製するためのメソッド等を呼ぶなどの手続きが必要です。

int[] ary1 = { 11, 22, 33, 44 }; // 4 つの要素を持った配列を 1 つ作る
int[] ary2 = ary1.ToArray(); // Clone メソッドあるいは ToArray メソッドを使い、同じ情報をもった別の配列をもう 1 つ作る(複製体を作成したということ)
ary1[0] = 9; // ary1 の先頭要素を 11 から 9 に変更する
int result = ary2[0]; // 今度は ary2[0] は 11 のまま。(ary1 と ary2 は異なる配列を参照している)
引用返信 編集キー/
■100843 / inTopicNo.7)  Re[3]: 参照渡し、値渡しについて
□投稿者/ ビール呑み (8回)-(2022/11/01(Tue) 23:06:43)
2022/11/01(Tue) 23:57:21 編集(投稿者)

No100841 (しーや さん) に返信
「片方に代入するともう片方も連動する」という理解が混乱のもとのような気がします
(最初のうちは無理もないと思いますが)

こう考えてはどうでしょう?生徒を表す「Student」というクラスがあるとして

Student 山田 = new Student(); //[1]
Student 鈴木 = new Student(); //[2]

山田は生徒クラスをインスタンス化したものを指しています。鈴木も同様

でもここで、「山田 = 鈴木;」なんてことは普通はしません
(「classA = classB;」というのはあくまでもふるまいを説明するための例と考えましょう)

実際に使うとすれば次のような形

Student 学級委員 = 山田;

学級委員はStudentクラスなので、山田も鈴木もセットすることができます
そして、学級委員が山田のときに山田のプロパティが変更されると
学級委員のプロパティも連動して変更されたように見えるかもしれません

が、実際には、上記の[1]で生成された山田のインスタンスが変更されただけなのです

プログラマとしては、個々のインスタンスに対して操作をおこないたい場合もあれば、
学級委員として選ばれたStudentをピンポイントで操作したい場合もあるでしょう


変数というのは我々がコンピューターに対して指示を出すときの名札のようなものと捉えるといいかも
名札には好きな名前を書けるし、貼る場所も変えることができます
引用返信 編集キー/
■100844 / inTopicNo.8)  Re[1]: 参照型、値型について
□投稿者/ 伝説のカレー (50回)-(2022/11/02(Wed) 00:14:44)
Other classA = new Other();
// classA ─── Other

Other classB = new Other();
// classA ─── Other
// classB ─── Other

classA.Value = 10;
// classA ─── Other.Value ─── 10
// classB ─── Other

classB.Value = 20;
// classA ─── Other.Value ─── 10
// classB ─── Other.Value ─── 20

classA = classB;
// classA ─┐  Other.Value ─── 10
// classB ─┴─ Other.Value ─── 20

classB.Value = 30;
// classA ─┐  Other.Value ─── 10
// classB ─┴─ Other.Value ─── 30

図を描くとこんな感じです

引用返信 編集キー/
■100845 / inTopicNo.9)  Re[4]: 参照渡し、値渡しについて
□投稿者/ しーや (14回)-(2022/11/02(Wed) 15:30:23)
No100842 (魔界の仮面弁士 さん) に返信
> >>Other2インスタンスは、classA と classB の両方から参照されている状態です。
> 「クラス」と「インスタンス」の違いは分かりますか?
指摘されて気づきました。念のため再確認してきます。

> 一方、Other が class(参照型) であった場合は、「classA = classB;」というのは
> インスタンスのコピーではなく、そのインスタンスの「参照情報」をコピーする動作となります。
> 参照がコピーされたとしても、同じ実体(インスタンス)を複数の変数から参照しているだけなので、
> classA.Value を書き換えると、同じ実体の情報を見ている classB.Value も連動して変化します。
配列の解説も読んで思ったのが、自分は「参照」というのがいまいち掴めていないのかもしれません。
参照は「インスタンスが情報にアクセスするルート(手段)」みたいな捉え方でいいですかね。
classA → other ← classB
(1) (2)
このotherにつなぐルート(矢印)が参照で、
classA = classB
をすることでclassAは(2)のルートでアクセスするようになった。みたいな。

引用返信 編集キー/
■100846 / inTopicNo.10)  Re[4]: 参照渡し、値渡しについて
□投稿者/ しーや (15回)-(2022/11/02(Wed) 15:39:17)
No100843 (ビール呑み さん) に返信
わかりやすかったです。
おかげでグッチャグチャだったのが少し整理できました。
ありがとうございます。
引用返信 編集キー/
■100847 / inTopicNo.11)  Re[2]: 参照型、値型について
□投稿者/ しーや (16回)-(2022/11/02(Wed) 15:43:45)
No100844 (伝説のカレー さん) に返信
自分は図にしたほうが理解しやすいのかもしれません。すんなり飲み込めました。

ーーーは前(classAなど)が後ろ(Otherなど)にアクセスするルートであり「参照」である。という考え方であってますか?
引用返信 編集キー/
■100848 / inTopicNo.12)  Re[3]: 参照型、値型について
□投稿者/ 伝説のカレー (51回)-(2022/11/02(Wed) 16:03:11)
No100847 (しーや さん) に返信

> ーーーは前(classAなど)が後ろ(Otherなど)にアクセスするルートであり「参照」である。という考え方であってますか?

あってます
線の向きも表したかったんですけど罫線素片には向きを表す記号がないんですよね
矢印の文字を使うと線がズレるので向きは省略してました

引用返信 編集キー/
■100850 / inTopicNo.13)  Re[4]: 参照型、値型について
□投稿者/ しーや (17回)-(2022/11/03(Thu) 16:10:14)
2022/11/03(Thu) 16:10:27 編集(投稿者)

No100848 (伝説のカレー さん) に返信
ありがとうございます
皆さんのお陰で完璧に疑問が消えました。
ありがとうございました!
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ