連載

C#入門

第3回 クラスとオブジェクト

(株)ピーデー
川俣 晶
2001/04/21


staticの効力

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

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

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

   1: class Person
   2: {
   3:   public static string name;
   4:   public static int age;
   5: }
クラス内の変数にstaticを指定する。しかしこのクラスを利用するプログラムはコンパイルエラーになる

 すると、このクラスを利用するプログラムはコンパイルエラーとなる。taro.nameなどの書式がすべてエラー扱いになる。staticの付いた変数はインスタンスではなくクラスに属するものなので、変数名のtaroではなく、クラス名のPersonを使って、Person.nameと書かねばならない。このルールに従って、上記の例のメソッドtest( )を書き換えると以下のようになる。

   1: static void test()
   2: {
   3:   Person taro;
   4:   Person hanako;
   5:   taro = new Person();
   6:   Person.name = "太郎";
   7:   Person.age = 20;
   8:   hanako = new Person();
   9:   Person.name = "花子";
  10:   Person.age = 17;
  11:   Console.WriteLine(Person.name);
  12:   Console.WriteLine(Person.name);
  13: }
staticを指定した変数にアクセスするには、クラス名を使用する

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

Personクラスの変数宣言にstaticを追加した場合の実行結果
Personクラスの変数をstaticとして宣言すると、インスタンスなど生成しなくても、これらの変数にPerson.nameなどとしてアクセスできるようになる。ただし、この場合の変数はクラスに1つしかないので、前述したように、2つのインスタンスを生成して、2人の情報を別に管理することはできない。

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

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

アクセスの制御

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

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

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

オブジェクト指向ではないプログラムでの変数アクセス
プログラムのあらゆる場所から、あらゆる変数にアクセス可能なモデルでは、プログラムのどの部分が、どの変数をどのような目的で使っているのか分かりにくい。
 
オブジェクト指向のプログラムでの変数アクセス
オブジェクト指向のプログラムでは、外部から使われたくない変数と、外部から使われたい変数をクラスを使って明示的に指示することができる。

 さらに理想を言えば、変数はいっさい外に見せないという方法もある。そのために、C#にはインデクサやプロパティという機能があるのが、この連載でいずれ紹介することになるだろう。

 このような理由で、C#の変数やメソッドには、アクセスを制限する機能が存在する。アクセスの制限方法を指定するには、あらかじめ定められたキーワードを、変数やメソッドの宣言に付けるだけでよい。キーワードは複数あるが、ここでは、publicとprivateの2つだけ紹介しよう。publicは、外部からの無制限のアクセスを許すもの。privateは逆に外部からのアクセスはすべて拒絶するものである。もちろん、privateを指定した場合でも、同じクラスの中からは自由に利用することができる。

 具体的な例を見てみよう。今回の最初に紹介したPersonクラスのpublicをprivateに変更してみよう。

   1: class Person
   2: {
   3:   private string name;
   4:   private int age;
   5: }
クラス内の変数にprivateを指定する。クラスの外部からこれらの変数にはアクセスできなくなる

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

   1: class Person
   2: {
   3:   private string name;
   4:   private int age;
   5:   void test()
   6:   {
   7:     Console.WriteLine(name);
   8:   }
   9: }
同一クラスの内部からは、privateな変数にアクセスできる

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

まとめ

 この連載は、オブジェクト指向に深く入り込むつもりはないのだが、それでもオブジェクト指向は難物である。知らない人には、とても難しい内容と感じられたかもしれない。もしかしたら、今回はこの連載で最大級の難関となるかもしれない。だが、オブジェクト指向はプログラマを苦しめるために存在するわけではない。これを乗り越えれば、楽しい世界が待っているのである。

 今回はオブジェクト指向のすべての特徴を語り尽くせなかった。次回は、オブジェクト指向の特徴の1つである「継承」という機能を紹介するとともに、コンポーネント指向という言葉の意味も解説しよう。

 それでは次回もLet's See Sharp!End of Article


 INDEX
  C#入門 第3回 クラスとオブジェクト
    1.オブジェクト指向とコンポーネント指向
    2.クラスとインスタンス
  3. staticの効力
 
「C#入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間