プログラミング入門(4)〜クラスの概念

下記のページを参考にプログラミングの勉強を行います。
クラスとは - クラスの概念 - Ruby入門
クラスの定義とオブジェクトの作成 - クラスの概念 - Ruby入門
インスタンスメソッド - クラスの概念 - Ruby入門
インスタンス変数 - クラスの概念 - Ruby入門
initializeメソッド - クラスの概念 - Ruby入門
アクセスメソッド - クラスの概念 - Ruby入門
定数 - クラスの概念 - Ruby入門
クラス変数 - クラスの概念 - Ruby入門

クラスとは


クラスとは


クラスは次のようなもの。

class Car
  def initialize(carname)
    @name = carname
  end

  def dispName
    print(@name)
  end
end

オブジェクト指向でないプログラムでは、行いたい処理を順に列挙していくが、オブジェクト指向ではまず何を行う物体の設計図を作成し、設計図から物体(オブジェクト)を作成し、その物体に処理をさせる。
クラスは物体(オブジェクト)を作成する元になる設計図であり、作成する物体がどのようなものなのかを定義する。

定義したクラスからオブジェクトを作成し、そのオブジェクトに実際の処理をさせる。

サンプルプログラム

class Car
  def initialize(carname)
    @name = carname
  end

  def dispName
    print(@name)
  end
end

car = Car.new("crown")
car.dispName

f:id:ayaketan:20111212113130j:image

「車」の設計図であるクラスを定義し、クラスからオブジェクトを作成した後で、オブジェクトに対して名前を画面に表示させている。

クラスの定義とオブジェクトの作成


クラスの定義


クラスの定義は次のように行う。

class クラス名

end

クラスは「class」から始まり「end」で終わりとなる。そしてクラスにはクラス名を指定する。

クラス名はクラスを識別するための名前で、大文字のアルファベットから始まる。
例えば「Car」というクラスを定義は次のように行う。

class Car

end

オブジェクトの作成


クラスはあくまで設計図なので、実際に何かを行わせるには、クラスからオブジェクトを作成する必要がある。すべてのクラスにはいくつかのクラスに対する動作を行わせるクラスメソッドが用意されている。
ここではクラスからオブジェクトを作成するための「new」メソッドを使用してみる。

class クラス名

end

変数名 = クラス名.new()

クラスからオブジェクトを作成するには、クラス名に対して「new」メソッドを実行する。メソッドはクラス名の後にドット「.」をつけて記述する。そして作成されたオブジェクトを格納するための変数を指定する。

class Car

end

car1 = Car.new()

クラスは設計図なので設計図から複数のオブジェクトを作成することができる。作成されたオブジェクトはそれぞれクラスに基づいた動作をするが、別々に操作することができる。

class Car

end

car1 = Car.new()
car2 = Car.new()

サンプルプログラム

class Car
  def initialize(carname)
    @name = carname
  end

  def dispName
    print(@name, "\n")
  end
end

car1 = Car.new("crown")
car1.dispName

car2 = Car.new("civic")
car2.dispName

f:id:ayaketan:20111212113207j:image

今回のサンプルでは「車」の設計図であるクラスを定義し、クラスから2つのオブジェクトを作成している。オブジェクトの元になっているクラスは同じだが、異なる初期化処理を行っているため、同じメソッドを実行させても別の動作を行う。

インスタンスメソッド


インスタンスメソッド


クラスは何かを行うための設計図。そこで具体的に何をさせたいかをクラスの中に記述していく必要がある。その処理を記述するのがメソッド。

メソッドは実行する一連の処理をまとめたもの。
ただし、通常のメソッドがプログラムからいつでも呼び出せるのに対し、クラス内に記述されたメソッドはクラスから作成されたオブジェクトしか呼び出すことができない。このようなメソッドをインスタンスメソッドと呼ぶ。

class クラス名
  def メソッド名(引数1, 引数2, ...)
    処理
  end
end

下記は簡単なインスタンスメソッドの例。
引数がないメソッドの場合は括弧を省略してもかまわない。

class Car
  def dispClassname
    print("Car class\n")
  end

  def dispString(str)
    print(str,"\n")
  end
end

インスタンスメソッドの呼び出し


定義されたインスタンスメソッドはクラスのオブジェクトから呼び出すことができる。

class Car
  def dispClassname
    print("Car class\n")
  end

  def dispString(str)
    print(str,"\n")
  end
end

car = Car.new
car.dispClassname
car.dispString("crowm")

f:id:ayaketan:20111212113235j:image

オブジェクトからメソッドを呼び出すには、オブジェクトの後にドット「.」をつけてメソッド名を記述する。引数がある場合は括弧の後に引数をカンマで列挙して記述する。引数がない場合はメソッド名だけでかまわない。

オブジェクト名.メソッド名(引数1, 引数2, ...)
オブジェクト名.メソッド名

またドットの代わりにコロン「:」を2つ続けて次のように記述することもできる。

オブジェクト名::メソッド名(引数1, 引数2, ...)
オブジェクト名::メソッド名

インスタンス変数


インスタンス変数


オブジェクトの中で値を保存しておくために利用されるのがインスタンス変数。

ローカル変数をメソッド内で使用することも可能ですが、ローカル変数は一度メソッドを抜けてしまえば値は消えてしまう。

インスタンス変数はクラス内の全メソッドで共通して使用することができる。
最初にどこかのメソッドで使用された時点でインスタンス変数は作成され、一度作成されたインスタンス変数は他のメソッドで値を取り出したり格納したりすることができるようになる。

また、インスタンス変数はクラスから作成されるオブジェクトごとに固有のものとなる。例えば、一つのオブジェクトの中でインスタンス変数に格納された値と、別のオブジェクトの中でインスタンス変数に格納された値は別のものとなる。

インスタンス変数の変数名は「@name」などのように「@」で始まる。ローカル変数などと同じく値が格納された時点から使用できるようになる。

class クラス名

  def メソッド名
    @name = 値
  end

end

インスタンス変数はインスタンス変数が使用可能になったインスタンスメソッド以外のインスタンスメソッド内でもしいようすることができる。

class Car
  def setName(str)
    @name = str
  end

  def dispName()
    print(@name,"\n")
  end
end

car = Car.new
car.setName("crowm")
car.dispName()

f:id:ayaketan:20111212113258j:image

上記の場合は「setName」メソッドによってインスタンス変数「@name」に値が格納され、「dispName」メソッドのよってインスタンス変数「@name」に格納されている値を表示している。

インスタンス変数の割り当て


クラスからは複数のオブジェクトを作成することができるが、インスタンス変数はオブジェクト毎に異なる値を割り当てることができる。

class Car
  def setName(str)
    @name = str
  end

  def dispName()
    print(@name,"\n")
  end
end

car1 = Car.new
car1.setName("crowm")

car2 = Car.new
car2.setName("civic")

car1.dispName()
car2.dispName()

f:id:ayaketan:20111212113315j:image

上記のプログラムでは「car1」オブジェクト「car2」オブジェクトには別々のインスタンス変数「@name」が割り当てられているので、それぞれのオブジェクトに対してメソッドを使って値を格納した場合、上書きされることなく異なる値を格納することができる。

initializeメソッド


initializeメソッド


インスタンスメソッドの中で「initialize」という名前が付けられたメソッドは特殊なメソッドで、このメソッドをクラス内に記述した場合には、オブジェクトが作成されるときに自動的に呼び出される。
Javaなどのコンストラクタと同じ。

「initialize」メソッドを使うことでオブジェクトを作成時に必ず実行したい処理をメソッドを呼び出すことなく実行することができる。
次の例では「initialize」メソッドの中でインスタンス変数を初期化している。

class Car
  def initialize()
    @name = "未定義"
  end
end

car = Car.new()

これは「initialize」メソッドを使わずに通常のインスタンスメソッドを使って次のように記述した場合と同じ。

class Car
  def init()
    @name = "未定義"
  end
end

car = Car.new()
car.init()

「initialize」メソッドに引数を指定する


他のメソッドと同じく「initialize」メソッドも呼び出すときに引数を指定して呼び出すことで、メソッドに値を渡すことができるが、「initialize」メソッドは自動的に呼び出されるメソッドなので、「initialize」メソッドに渡す値はクラスメソッドの「new」メソッドの引数に指定する。

class Car
  def initialize(carname)
    @name = carname
  end
end

car = Car.new("civic")

また、他のメソッドと同じく引数に初期値を設定することも可能。

class Car
  def initialize(carname="未定義")
    @name = carname
  end
end

car1 = Car.new("civic")
car2 = Car.new()

サンプルプログラム

class Car
  def initialize(carname="未定義")
    @name = carname
  end

  def dispName()
    print(@name, "\n")
  end
end

car1 = Car.new("civic")
car2 = Car.new()

car1.dispName()
car2.dispName()

f:id:ayaketan:20111212113336j:image

アクセスメソッド


アクセスメソッド


クラスの中で使われているインスタンス変数はクラスの外からは参照したり値を変更したりすることができない。参照する場合も変更したい場合もインスタンスメソッドを経由して行う必要がある。

class Car
  def initialize(carname="未定義")
    @name = carname
  end
  
  def getName()
    return @name
  end
  
  def setName(newName)
    @name = newName
  end
end

car = Car.new()
car.setName("civic")
print(car.getName())

このようにメソッドを定義することでオブジェクトからインスタンス変数の参照や更新が行えるが、多くのインスタンス変数があるが愛はメソッドを定義するだけでも大変。
そこで、インスタンス変数への参照屋更新が簡単に行えるようにアクセスメソッドと呼ばれるものが用意されている。

用意されているアクセスメソッドは次の3つ
attr_reader:変数名 …参照が可能
attr_writer:変数名 …更新が可能
attr_accessor:変数名 …参照と更新が可能

使い方は次のようになる。

class Car
  def initialize(carname="未定義")
    @name = carname
  end
  attr_accessor:name
end

上記のように対象となるインスタンス変数名に対して「attr_reader」「attr_writer」「attr_accessor」のいずれかを使って上記のように記述することでインスタンス変数の参照や更新用のメソッドを個別に定義する代わりとなる。

サンプルプログラム

class Car
  def initialize(carname="未定義")
    @name = carname
  end
  attr_accessor :name
end

car = Car.new()
car.name = "civic"
print(car.name)

f:id:ayaketan:20111212113359j:image

「オブジェクト名.変数名」で参照したり更新したりが直接行える。
クラス外からインスタンス変数が直接操作できるようになったわけではなく、参照や更新が行えるメソッドが自動的に作成されたと考えること。

定数


定数


クラス内で定数を定義することができる。
定数はアルファベットの大文字で始まる変数名に対して一度だけ値を格納することができる。

class Reji
  SHOUHIZEI = 0.05

  def initialize(init=0)
    @sum = init
  end
  def kounyuu(kingaku)
    @sum += kingaku
  end
  def goukei()
    return @sum * (1 + SHOUHIZEI)
  end
end

reji = Reji.new(0)
reji.kounyuu(100)
reji.kounyuu(80)
print(reji.goukei())

f:id:ayaketan:20111212113422j:image

上記の例ではクラス「Rei」内で定数「SHOUHIZEI」を定義している。なお、クラス内の場合もメソッドの中では定数は定義できない。

クラス外から定数の参照


クラス内で定義された定数は、次のように記述することでクラス外から参照することができる。

クラス名::定数名

なお、「::」はメソッドの場合の呼び出しでも使用できるが、メソッドのように「.」だけを使って「クラス名.定数名」のようには使用できない。

サンプルプログラム

class Reji
  SHOUHIZEI = 0.05

  def initialize(init=0)
    @sum = init
  end
  def kounyuu(kingaku)
    @sum += kingaku
    print("お買い上げ:", kingaku, "\n")
  end
  def goukei()
    return @sum * (1 + SHOUHIZEI)
  end
end

reji = Reji.new(0)
reji.kounyuu(100)
reji.kounyuu(80)
print("合計金額:", reji.goukei(), "\n")

print("消費税率:", Reji::SHOUHIZEI)

f:id:ayaketan:20111212113448j:image

クラス変数


クラス変数


クラス内で使用するインスタンス変数はクラスから作成されたオブジェクト毎に異なる値を格納できるものであったのに対して、クラス変数はクラスから作成されたすべてのオブジェクトで共有される変数となる。

すべてのオブジェクトで共有されるため、あるオブジェクトを使ってクラス変数の値を変更した場合は、別のオブジェクトでクラス変数を参照すると更新された値を取得することになる。

クラス変数の変数名は「@@name」などのように「@@」で始まる。
ローカル変数などと同じく値が格納された時点から使用できるようになる。

class クラス名
  @@name = 値
end

クラス変数はメソッド内ではなく、定数と同じクラス内のメソッド内ではない場所で定義する。

サンプルプログラム

class Car
  @@count = 0

  def initialize(carname="未定義")
    @name = carname
    @@count += 1
  end

  def getCount()
    return @@count
  end
end

car1 = Car.new("crown")
car2 = Car.new("civic")
car3 = Car.new("alto")

print("現在生成されたオブジェクト数:", car1.getCount())

f:id:ayaketan:20111212113517j:image

上記のサンプルの場合、まず「@@count = 0」でクラス変数の初期化が行われている。この初期化は最初のオブジェクトが作成されたときに実行されるが、それ以降のオブジェクトが作成された時には実行されない。
次に「initialize」メソッドの中でクラス変数の値を「+1」している。これはオブジェクトが実行される度に実行されるので、オブジェクトが作成されるたびにクラス変数の値が増加していくことになる。
今回は「car1」オブジェクトを使ってクラス変数の値を取得したが、他のオブジェクトを使ってクラス変数を取得しても同じ結果になる。