オブジェクト指向

オブジェクト指向の考え方

ここではC#言語の特徴である、オブジェクト指向について、詳しく説明します。オブジェクト指向とは、あらゆるものを、すべて「モノ」として表現するという考え方のことを言います。オブジェクト指向の、オブジェクト(Object)とは、英語で「モノ」を表す言葉です。

例えば、自動車を運転する際には、自動車内部の仕組みを理解する必要はありません。ただ運転方法だけを知っていれば、それだけで自動車を使うことができます。

つまり、「自動車」というオブジェクトは、動作させる仕組みがすでに内部に組み込まれていることから、それを利用するためには、仕組みを知る必要は一切なく、ただアクセルを踏む、ハンドルを切るなどといったような適切な操作をすればよいことになります。(図6-1参照)

図6-1.オブジェクト指向の考え方
オブジェクト指向の考え方:車を例に

オブジェクトには、操作にあたる、メソッドと呼ばれる部分と、データにあたるフィールドがあります。自動車の例で言えば、「発進する」「停止する」などがそのメソッドで、フィールドは、スピード、走行距離、といったところでしょう。(表6-1参照)

表6-1:自動車オブジェクトのメソッドとデータ
フィールド スピード
走行距離
排気量
メソッド 発信する
停止する
曲がる

クラスとオブジェクト

以上で、だいたいオブジェクト指向の考え方が理解できたかと思います。そこで、ここではさらに、クラスという概念について説明します。前述の、自動車という例を用いて説明すると、通常、世の中には、自動車がたくさん存在します。

オブジェクトは、こういった、ここの物体をさす場合に用いられる概念で、このほかに、インスタンスという呼び名もあります。

ただ、こういった自動車も、もとはひとつの設計図を元に大量生産されているはずなのです。この、設計図にあたるものを、クラスと言います。つまり、クラスがなければ、オブジェクトもありえないのです。以上が、基本的なオブジェクト指向の考え方です。オブジェクト指向には、このほかに様々な概念がありますが、今後適宜紹介していきます。(図6-2.参照)

図6-2.クラスとオブジェクト
クラスとオブジェクト

サンプルプログラム

配列変数について詳しく説明する前に、まずは以下のプログラムを入力・実行してみてください。プロジェクトSample601を作成し、ファイルPerson.csを追加し、以下のプログラムを入力してください。

プロジェクト:Sample601/ファイル名Person.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample601
{
    class Person
    {
        //  名前(フィールド)
        public string name = "";
        //  年齢(フィールド)
        public int age = 0;
        //  情報の表示(メソッド)
        public void ShowAgeAndName()
        {
            Console.WriteLine("名前:{0} 年齢:{1}", name, age);
        }
        //  情報の設定
        public void SetAgeAndName(string name, int age)
        {
            this.name = name;
            this.age = age;
        }
    }
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample601
{
    class Program
    {
        static void Main(string[] args)
        {
            Person p1, p2;
            p1 = new Person();  //  一つ目のPersonクラスのメソッドのインスタンスを生成
            p2 = new Person();  //  二つ目のPersonクラスのメソッドのインスタンスを生成
            p1.name = "山田太郎";   //  フィールドnameに値を代入
            p1.age = 19;            //  フィールドageに値を代入
            p2.SetAgeAndName("佐藤花子", 23);   //  setAgeAndName()メソッドで、nameとageを設定
            //  showAgeAndName()メソッドで、それぞれのインスタンスのnameとageを表示
            p1.ShowAgeAndName();
            p2.ShowAgeAndName();
        }
    }
}
実行結果
名前:山田太郎 年齢:19
名前:佐藤花子 年齢:23

今までと違い、ソースコードが複数になりました。Personというクラスのインスタンスを生成し、処理を行っているのが、Sample601です。以下、その詳細を見てみましょう。

インスタンスの生成

すでに述べたとおり、オブジェクト指向の考え方では、クラスから、オブジェクト(インスタンス)を生成し、それを操作するというのがオブジェクト指向の考え方です。C#では、クラスの宣言は、classというキーワードが用いられます。そのクラスのインスタンスを生成しているのが、Program.csの14行目、15行目です。

インスタンスの生成
p1 = new Person(); // 一つ目のPersonクラスのメソッドのインスタンスを生成
p2 = new Person(); // 二つ目のPersonクラスのメソッドのインスタンスを生成

これにより、変数p1およbp2は、Personクラスのインスタンスになります。(図6-3.参照)

図6-3.インスタンスp1,p2の生成
インスタンスp1,p2の生成

フィールド

クラス、Personには、フィールドメソッドが存在します。まずは、フィールドから説明しましょう。Personクラスには、以下のフィールドが存在します。(表6-2.)

表6-2.Personのフィールド
フィールドの名 初期値
age int 0
name string ""

フィールドには、初期値を代入することが可能です。初期値は、変数の宣言の後に"="をつけて、そのあとに記述されます。(Person.cs、12,14行目)これらの値は、インスタンス生成と同時に代入されます

これにより、インスタンスsは、int型のageという変数と、string型のnameという変数を持つことができるようになります。クラスの外部である、Program.csからは、以下のようにアクセスします。(16行目、17行目)

フィールドへの値の代入
p1.name = "山田太郎"; // フィールドnameに値を代入
p1.age = 19; // フィールドageに値を代入

これにより、インスタンスp1のフィールドageには、19という値が、nameには、"山田太郎"という文字列が代入されます。

メソッド

続いて、操作であるメソッドについて説明しましょう。メソッドとは、他の言語では、関数(かんすう)と呼ばれる処理です。何らかのデータを外部から受け取り、それをもとに処理をして、実行結果を出力するというものです。例えば、Person.csの16行目から19行目を見てください。

メソッド①:ShowAgeAndName
public void ShowAgeAndName()
{
    Console.WriteLine("名前:{0} 年齢:{1}", name, age);
}

このメソッドを呼び出しているのが、Program.csの20行目、および21行目です。メソッドを呼び出す方法は、(インスタンス名).(メソッド名)という形をとります。

ShowAgeAndNameメソッドの呼び出し
p1.ShowAgeAndName();
p2.ShowAgeAndName();

このメソッドは、フィールドnameおよび、ageを表示します。p1に関しては、Program.csの16行目および、17行目で、nameおよび、ageに、「山田太郎」「19」を代入しているために、「名前:山田太郎 年齢:19」が出力されます。

メソッドの引数

では、p2の実行結果が、「名前:佐藤花子 年齢:23」とるのは、なぜでしょう?これは、Personクラスのもう一つのメソッドである、SetAgeAndName()によるものです。

メソッド②:SetAgeAndName
public void SetAgeAndName(string name, int age)
{
    this.name = name;
    this.age = age;
}

このメソッドには、()内に、,で区切って二つの変数が定義されています。この変数のことを、引数(ひきすう)と言います。この値は、このメソッドを呼び出すときに、外部から与えられます。

Person.csでは、この引数で与えらたnameおよびageを、フィールドであるnameとageに代入しています。この二つは同じ名前なので、それらを区別するために、フィールドには、先頭にthisをつけています。

thisは、自分自身のインスタンスを表す記号で、これを先頭につけることにより、その変数がフィールドであることを示しています。これにより、引数の値が同名のフィールドに代入されます。(図6-4.参照)

図6-4.SetAgeAndNameメソッドの呼び出しイメージ
SetAgeAndNameメソッドの呼び出しイメージ

以上より、このサンプルは、p1に関しては、nameおよびageフィールドに値を直接代入し、p2に関してはSetAgeAndName()メソッドにより、同様に値を設定して、その値をShowAgeAndName()メソッドで表示していることがわかります。

p1およびp2は、共通のフィールドおよびメソッドを持っていますが、その値や実行結果は、インスタンスが異なるので違います。

メソッドの戻り値

ところで、これらメソッドの先頭についている、void(ボイド)は、いったい何を意味するのでしょうか?メソッドは、場合によっては、演算結果などといった値を返すことがあります。そのようなものを、戻り値と言います。ただ、戻り値がないメソッドを作る場合は、このように、戻り値の型として、voidを指定します。

オーバーロード

サンプルプログラム

さらに、クラスのインスタンスを生成いし、実行するプログラムを見てみましょう。以下のサンプルを入力し、実行してみてください。

プロジェクト:Sample602/ファイル名Calc.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample602
{
    class Calc
    {
        //  二つの整数の引数の和を求める
        public int Add(int a,int b){
            return a + b;
        }
        //  三つの整数の引数の和を求める
        public int Add(int a, int b, int c)
        {
            return a + b + c;
        }
    }
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample602
{
    class Program
    {
        static void Main(string[] args)
        {
            Calc calc = new Calc();
            int a = 1,b = 2,c = 3;
            int ans1 = calc.Add(a, b);
            int ans2 = calc.Add(a, b, c);
            Console.WriteLine("{0} + {1} = {2}", a, b, ans1);
            Console.WriteLine("{0} + {1} + {2} = {3}", a, b, c, ans2);
        }
    }
}
実行結果
1 + 2 = 3
1 + 2 + 3 = 6

戻り値のあるメソッドの呼び出し

Program.csの15行目で、CalcクラスのAdd()メソッドを呼び出しています。Calcクラスには、Add()メソッドがふたつ存在しますが、この場合、引数が二つあるため、Calc.csの12行目から14行目に定義されている、引数2つのAdd()メソッドが呼ばれます。

このメソッドの先頭に、intと書いてありますが、これは、メソッドの戻り値が整数型であるということを意味します。戻り値を返すのは、return文で、この場合、二つの引数a,bの和を返しています。メソッドを呼び出した側では、この戻り値を利用しています。(図6-5.参照)

図6-5.Addメソッドのイメージ
Addメソッドのイメージ

return文で返される戻り値のデータ型は、原則的にメソッドの先頭で定義されている、戻り値の型と一致していなくてはなりません。

オーバーロード

ところで、Program.csの16行目では、同じくAdd()メソッドを呼びだしていますが、その時、引数は、3つの引数が与えられています。このとき、Calc.csの16行目から19行目で定義されている、引数3つのAdd()メソッドが呼び出されます。

Calcメソッドには、このように同名のメソッドが複数定義されています。これを、オーバーロードと言います。ただし、その時同じ名前のメソッドは、それぞれ引数および戻り値の型が異なっている必要があります


練習問題 : 問題5.