魔法のキーワード

ホームC#入門講座第3章:ものづくり技術論 > 魔法のキーワード

魔法のキーワード

new

杖をひとふりするだけで、好きなものが瞬時に現れる。それが魔法だとすれば、newこそ魔法のキーワードです。

Menseki men = new Menseki();

newキーワードに続けてクラス名を記述し、かっこを付けると、メモリ上にクラスを基にしたオブジェクトが作られます。そのオブジェクトは「実体」であり、インスタンスとも呼ばれます。

newキーワードはいかなる設計図でも一瞬で実体化し、メモリ上に物体を作り上げます。これこそが目に見えないものづくりであり、newはありとあらゆる技法を知りつくした職人のごとく振る舞います。

参照

ここで一つ、重要なことを学ばなくてはなりません。上のステートメントでMenseki型の変数menに代入されるものについてです。

たとえば、int型の変数を扱う場合は単純でした。

int i = 10;

このとき、iには10という値が入ります。このように、値が直接入る変数を「値型」といい、doubleやcharも同じ「値型」です。

しかし、上のMenseki型は値型ではなく「参照型」です。newキーワードによってメモリ上にオブジェクトが生成されますが、変数menに代入されるのはそのオブジェクトのあるメモリの住所です。オブジェクトそのものではなく、オブジェクトの在りか、メモリの住所が代入されます。

例えば、Houseというクラスがあり、以下のようにオブジェクト化したとします。

House myHouse = new House();

仮りにメモリ上の住所が現実の住所のように表されると仮定します。すると、new House()によって「愛媛県松山市・・・」という住所に家が建つのですが、myHouseという変数には「愛媛県松山市・・・」という住所そのものが格納されます。myHouseという変数は、その住所を通じて実体の家にアクセスします。

このように作られているのは、オブジェクトそのものを変数に代入すると、とても処理が重くなるからです。数値の場合はそのものを代入して操作しても問題ないのですが、オブジェクトはとてもメモリを消費します。そのため、変数にはそのメモリの位置だけを記憶するようにしているのです。

実は string型 もこのような「参照型」の一つです。

string str = "Hello, World!";

このとき、"Hello, World!"は実際にメモリ上に作られますが、変数strに入るのはその文字列ではなく、文字列のある位置です。

ドット演算子

変数menには実体としてのMensekiオブジェクトのメモリ上の位置が格納されています。そこからプロパティRにアクセスするにはドット演算子(スコープ演算子)の「.」を用います。

men.R = r;

men.Circle()

メソッドも同様です。オブジェクトのメンバにアクセスするにはドットを用います。

ドットには3つの意味があります。このように、メンバにアクセスするドットのほかに、前回紹介した「System.Windows.Forms.Form」のドットもあります。

これは「System.Windows.Forms名前空間のFormクラス」です。このように、最初の2つは名前空間同士をつなぐものであり、ヒエラルキーな構造を示します。最後の1つは名前空間とクラスをつなぐものです。つまり、「名前空間.名前空間」と「名前空間.クラス」と「クラス.メンバ」という3つの使い方があることに注意してください。

最初のうちは System.Windows.Forms.Form のどれがクラスか分からないという状態に陥ってしまいます。ですが、同じドットでも3つの場合があることに注意すれば、より素早い理解が可能となるでしょう。

コンストラクタ

最後に、クラス名の後についているカッコは気になりませんか? これには意味があります。

クラスは実体化する際に処理をすることができます。その処理は「コンストラクタ」に記述されます。コンストラクタとは、クラスと同じ名前を持ったメソッドです。たとえば、StreamReaderクラスを見てください。

StreamReader sr = new StreamReader("/home/satoshi/test.txt");

newキーワードを用いて実体化する際に、ファイルのパスを指定しています。これはStreamReaderクラスにStreamReader()というメソッドを定義しているためです。そのようなメソッドをコンストラクタといいます。StreamReaderコンストラクタは次のように定義されています。

public StreamReader (string path)

コンストラクタの最大の特徴はクラスと同じ名前であることですが、もう一つの特徴は「返す値の型」がないことです。なぜなら、コンストラクタが返すのは常にオブジェクトであり、わざわざ指定する必要がないからです。もし、double などを指定してしまったら、StreamReader型の変数srには何が入るのでしょうか。

コラム:ポリモーフィズム

StreamReaderのコンストラクタ一覧を見てください。実は10個ものコンストラクタが存在します。

これらは全部同じメソッド名ですが、引数が違います。つまり、メソッドを識別する際はメソッド名だけでなく、引数も参考にされます。このように、メソッド名や引数など、識別するための要素をシグニチャと呼びます。

同様に、Console.WriteLine()メソッドも見てください。実にたくさんのオーバーロードが存在します。

Console.WriteLine("Hello, World!");
  (別物)
Console.WriteLine(10.5);

上の2つは、実は別々のWriteLine()メソッドです。一つは string 型の引数をとるように宣言されたWriteLine()メソッドで、もう一つは double 型の引数をとるように宣言されたWriteLine()メソッドです。型は極めて厳密なので、「WriteLine()はなんでも表示できる」という便利な機能は、このように引数を分けて宣言するということによって実現された成果なのです。

このような「メソッドのオーバーロード」はポリモーフィズムの一例です。オーバーロードによく似た言葉で「オーバーライド」というのもあります。これは継承にまつわるお話で、難しくなりすぎるのでここでは控えます。

ですが、何気なく使ってきた WriteLine() ですら、オブジェクト指向の恩恵によって実装されているという事実はすこし驚きではないですか? だから「Hello,World!プログラム」にはその言語の特徴が全てつまっており、プログラム世界への初めてのノックであると表現したのです。