理解度を確認しよう
C#でのデータの取り扱いには、分かりにくい面がある。もちろん、無意味に分かりにくいわけではなく、必要だから導入された機能が、「分かりにくさ」という副作用を起こしていると考えるべきだろう。もちろん、他のプログラム言語にも、分かりにくい部分はある。例えばVisual Basicであれば、データ型の自動変換という初心者泣かせの機能があるし、Cならポインタがハードルになるかもしれない。C#では、値型と参照型の違いを理解することが、そのような位置づけになるだろう。
そのようなわけで、今回のテーマは変数なのだが、特に値型と参照型で変わる変数の働きを重点的に見てみよう。変数に関しては、すでにこの連載のなかで、何度もサンプルソースで使用してきたので、いまさら変数とは何ぞや、という説明は行わない。その代わり、読者の理解度を試す意味で、今回は1個のサンプル・プログラムを示して、その結果がどのようになるか、ソースコードから予測していただこう。
今回のサンプルソースはこれである。
1: namespace ConsoleApplication9
2: {
3: using System;
4:
5: public class TestClass : ICloneable
6: {
7: public int n;
8: public object Clone()
9: {
10: return MemberwiseClone();
11: }
12: }
13: public struct TestStructs
14: {
15: public int n;
16: }
17: public class Class1
18: {
19: public static int Main(string[] args)
20: {
21: int testInt1,testInt2;
22: testInt1 = 123;
23: testInt2 = testInt1;
24: testInt1 = 456;
25: Console.WriteLine( "Answer1 testInt1={0}, testInt2={1}", testInt1, testInt2 );
26:
27: TestClass testClass1,testClass2;
28: testClass1 = new TestClass();
29: testClass2 = new TestClass();
30: testClass1.n = 123;
31: testClass2.n = testClass1.n;
32: testClass1.n = 456;
33: Console.WriteLine( "Answer2 testClass1.n={0}, testClass2.n={1}", testClass1.n, testClass2.n );
34:
35: TestClass testClass1a,testClass2a;
36: testClass1a = new TestClass();
37: testClass1a.n = 123;
38: testClass2a = testClass1a;
39: testClass1a.n = 456;
40: Console.WriteLine( "Answer3 testClass1a.n={0}, testClass2a.n={1}", testClass1a.n, testClass2a.n );
41:
42: TestClass testClass1b,testClass2b;
43: testClass1b = new TestClass();
44: testClass1b.n = 123;
45: testClass2b = (TestClass)testClass1b.Clone();
46: testClass1b.n = 456;
47: Console.WriteLine( "Answer4 testClass1b.n={0}, testClass2b.n={1}", testClass1b.n, testClass2b.n );
48:
49: TestStructs testStructs1,testStructs2;
50: testStructs1.n = 123;
51: testStructs2 = testStructs1;
52: testStructs1.n = 456;
53: Console.WriteLine( "Answer5 testStructs1.n={0}, testStructs2.n={1}", testStructs1.n, testStructs2.n );
54:
55: object testObject1,testObject2;
56: testObject1 = 123;
57: testObject2 = testObject1;
58: testObject1 = 456;
59: Console.WriteLine( "Answer6 testObject1={0}, testObject2={1}", testObject1, testObject2 );
60:
61: return 0;
62: }
63: }
64: } |
|
コンソールに6行の文字列を表示するサンプル・プログラム |
このプログラムを実行すると、コンソールに6行の文字列が表示される。このとき1行の文字列には、2個の数値が表示される。つまり、計12個の数値が画面に表示される。この12個の数値を、上記のソースコードから予測していただきたい。
ちなみに、本質とは関係ない部分でいくつか引っかかる部分があると思うので、それを先に解説しておく。
5行目で、TestClassという名前のクラスを宣言しているが、その後ろにICloneableというキーワードが見える。これは8行目でClone( )というメソッドを実装するために付け加えたものである。とはいえ、実はこのプログラムだけに関して言えば、ICloneableというインターフェイスの名前をここに書かなくても問題はない(インターフェイスについては第4回 「継承とインターフェイス」を参照)。なお、このClone( )というメソッドは、45行目で明示的に呼び出されている以外、他の個所ではいっさい動作に関与することはないことをお約束しよう。
10行目でMemberwiseCloneというメソッドを呼び出しているが、これはobject (System.Object)クラスのメンバで、オブジェクト全体の浅いコピーを作成する機能を持ったものである。「浅いコピー」とは、そのオブジェクトだけの複製を作ることを意味する。逆に深いコピーとは、オブジェクトから参照されるオブジェクトも含めたコピーを作成することだが、ここではそこまでの知識は必要ない。ともかく、MemberwiseClone( )メソッドは、まったく同じ内容を持った別のオブジェクトを作る、と理解してほしい。もう1つ余談を書くなら、5行目のクラス宣言で、スーパー・クラスの名前は書かれていないが、そのような場合はobject (System.Object)クラスが自動的に仮定される。そのため、特にobjectクラスの宣言を明示しなくても、object(System.Object)クラスのメソッドを呼び出せるというわけである。
では、しばし考えていただきたい。
更新履歴 |
【2001.6.13】本ページに掲載したサンプル・プログラムのソース・コード内の59行目に誤りがありました。お詫びし、正しいソース・コードに訂正させていただきます。 |
|
Insider.NET 記事ランキング
本日
月間