連載
» 2002年09月04日 00時00分 公開

連載 改訂版 C#入門:第3章 クラスとインスタンス (2/3)

[川俣晶(http://www.autumn.org/),(株)ピーデー(http://www.piedey.co.jp/)]

3-3 staticの効力

 前章までは、必ずstaticを付けると説明したが、本章では一部の例外を除き、ずっとstaticなしでやってきた。そもそも、staticとは何だろうか?

 staticの機能は、クラス自身が変数やメソッドを持てるようにすることである。通常、クラスは設計図であり、インスタンスを作った時点で変数が生まれる。ところが、staticを付けて変数を宣言すると、その変数はインスタンスを作らなくても最初から存在することになるのである。メソッドの場合は、インスタンスを作らなくても呼び出せることになる。

 ならば全部staticを付けてしまえば、いちいちインスタンスなど作らなくても済むので楽ではないかと思う人がいるかもしれない。だが、そうは問屋がおろさない。staticを付けた変数は、プログラムの中に実体が1個しか作られないのである。そのため、Personクラスを使ってtaroとhanakoの2人分の情報を扱う、というようなことはできなくなる。以下にその例を見てみる。クラスPersonの宣言を変更して、変数宣言にstaticを付けてみよう。List 3-7を参照されたい。

 1: class Person
 2: {
 3:   public static string name;
 4:   public static int age;
 5: }

List 3-7

 すると、このクラスを利用するプログラムはコンパイル・エラーとなる。taro.nameなどの書式がすべてエラー扱いになる。staticの付いた変数はインスタンスではなくクラスに属するものなので、変数名のtaroではなく、クラス名のPersonを使って、Person.nameと書かなければならない。このルールに従ってList 3-6を書き換えたソースは、List 3-8のようになる。

  1: using System;
  2:
  3: namespace Sample002
  4: {
  5:   class Person
  6:   {
  7:     public static string name;
  8:     public static int age;
  9:   }
 10:
 11:   class Test
 12:   {
 13:     static void test()
 14:     {
 15:       Person taro;
 16:       Person hanako;
 17:       taro = new Person();
 18:       Person.name = "太郎";
 19:       Person.age = 20;
 20:       hanako = new Person();
 21:       Person.name = "花子";
 22:       Person.age = 17;
 23:       Console.WriteLine(Person.name);
 24:       Console.WriteLine(Person.name);
 25:     }
 26:     [STAThread]
 27:     static void Main(string[] args)
 28:     {
 29:       Test.test();
 30:     }
 31:   }
 32: }

List 3-8

 このプログラムが、taroとhanakoの2名の情報を扱えないことは明白に分かるだろう。念のため実行結果はFig.3-3のようになる。

Fig.3-3

 さて、以上は変数に関するstaticの必要性に関する説明だが、メソッドのほうはどうだろうか? staticなメソッドは、明示的に特定のインスタンスにアクセスするような書き方をしないかぎり、staticではない変数にアクセスすることはできないという制限が生じてしまう。逆に、いくつもインスタンスを作る必要がなければ、最初からメソッドにstaticキーワードを付けておくと、インスタンスを作るという手順を省いてメソッドを呼び出せる。これまでのサンプル・ソースで、多くのメソッドにstaticが付いている理由はこれである。

 最後に1つだけ補足しておくと、プログラムが実行されたときに最初に実行されるメソッドは、いずれかのクラスに属するMainメソッドである。しかし、プログラムの開始時点ではどのクラスのインスタンスも作られていないので、Mainメソッドにはstaticを付けなければならない。

3-4 アクセスの制御

 本章の例であるクラスPersonでは、変数宣言にpublicというキーワードを付けている。これはアクセスを制御するためのキーワードの1つである。アクセスを制御するとは、別のクラスからの利用を許可したり禁止したりする制限を、プログラマーが自由に与えられるようにするということである。

 だが、なぜ制限をする必要があるのか? その理由は、プログラムのソース・コードから複雑さを取り除くためだ。例えば、すべての変数が無制限に利用できるプログラミング言語で書かれたプログラムがあるとしよう。そのプログラムのソース・コードを読んでいるうちに、ちょっと書き換えると性能が改善できることを発見したとしよう。書き換えを実行するとそれまで使われていた変数がいくつか不要になるので削除したとする。ところが、そうすると、予期しない場所からその変数が利用されていて、プログラムそのものが動作しなくなってしまうかもしれない。このような問題が起きないような修正方法を探すには、プログラム全体に目を配らなければならない。これではあまりにも問題が複雑になりすぎる。

 これを解決するためには、変数の利用を制限するとよい。あるクラスが内部処理のために用意した変数をほかのクラスからアクセスできないようにしてしまえば、それだけで、注意すべき変数の数がぐっと減る。アクセスできない変数とはどんな関係も生じることがないので、無視してよいからだ(Fig.3-4Fig.3-5参照)。

Fig.3-4

Fig.3-5

 さらに理想的な、変数をいっさいクラス外に見せないという方法もある。C#には、そのためのインデクサやプロパティという機能がある。これらについては後の章で詳しく説明する。

 このような理由で、C#の変数やメソッドには、アクセスを制限する機能が存在する。アクセスの制限方法を指定するには、あらかじめ定められたキーワードを変数やメソッドの宣言に付けるだけでよい。キーワードは複数あるが、ここでは、publicとprivateの2つだけ紹介しよう。publicは、プログラム内外からの無制限のアクセスを許すもの、privateはクラス内からのアクセスのみを許すものである。もちろん、privateを指定した場合は、別クラスからのアクセスはすべてコンパイラがエラーとする。

 具体的な例を見てみよう。本章の最初に紹介したPersonクラスのpublicをprivateに変更してみる。List 3-9を見てほしい。

 1: class Person
 2: {
 3:   private string name;
 4:   private int age;
 5: }

List 3-9

 この状態で、変数nameや変数ageを利用するプログラムをコンパイルしようとしてもエラーになってしまう。クラスPerson以外からこれらの変数を利用しようとしても、privateキーワードがすべて拒絶してしまうのである。しかし、同じクラスの内側からならアクセスできるので、List 3-10のように、Personクラスにメソッドを追加して、そこからアクセスすればまったく正常に機能する。

 1: class Person
 2: {
 3:   private string name;
 4:   private int age;
 5:   void test()
 6:   {
 7:     Console.WriteLine(name);
 8:   }
 9: }

List 3-10

 ちなみに、7行目にあるように、同じクラスの内部にある変数を使う場合は、taro.nameやPerson.nameのように書かなくても、ただ変数名(name)を書くだけでよい。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。