- クラスを「種類別に階層を作って分類する」 → 「継承」という仕組みを利用できる
ドリンク, フード
などの種類別ドリンク
>コーヒー, 紅茶, スムージー
のような階層
クラスの継承
商品
> 飲み物
の階層をクラス定義する場合
- まず商品を生成するクラス
Item
を定義する
class Item
def name
@name
end
def name=(text)
@name = text
end
end
- 次にドリンクを生成するクラス
Drink
を定義する
class Drink
def name
@name
end
def name=(text)
@name = text
end
def size
@size
end
def size=(text)
@size = text
end
end
- 上記の場合、下記の部分が重複した記述となる
- インスタンス変数を戻り値として返す
name
メソッド - 引数から受け取った名前を、インスタンス変数に代入する
name=
メソッド
- インスタンス変数を戻り値として返す
こういったケースの場合、クラス Drink
の上流(親)となるクラス Item
で定義されたメソッドを、下流(子)となるクラスに引き継ぐことができる → クラスの継承
継承クラスの定義方法
class クラス名 < スーパークラス
end
Drink
クラスではname
およびname=
メソッドは定義していないがclass Drink < Item
によって、Drink
クラスはItem
クラスに定義されたすべてのメソッドを呼び出せる
class Item
def name
@name
end
def name=(text)
@name = text
end
end
class Drink < Item
def size
@size
end
def size=(text)
@size = text
end
end
drink = Drink.new
drink.name = "coffee" # (*)
drink.size = "small"
p "#{drink.name} : #{drink.size} size"
# "coffee : small size"
Item
クラス- 継承元となるクラス
- スーパークラス(親クラス)
Drink
クラス- 継承先となるクラス
- スーパークラス(子クラス)
親クラスと子クラスのどちらにメソッドを加えるか
上記の例に対して、さらなるメソッドを追加する場合
価格
を設定・取得するメソッドDrink
だけに限定されず、(例えばFood
など)商品全般に共通する- 親クラス
Item
にメソッドを定義するべき
- 親クラス
ホット or アイス
を設定・取得するメソッドDrink
に必要なメソッドでも、(例えばFood
など)商品全般に共通するとは限らない- 子クラス
Drink
にメソッドを定義するべき
- 子クラス
Ruby に用意されているクラスたちの継承関係を確認 ancestors
- 整数クラス
Integer
や小数クラスFloat
は、数値クラスNumeric
を継承して作られている- 例)数値が
0
か判定するzero?
メソッドは、親クラスNumeric
に定義されている- 親クラスのメソッドを継承している整数クラス・小数クラスともにこのメソッドを実行できる
- 例)数値が
p 0.class # Integer
p 0.0.class # Float
p 0.zero? # true
p 0.0.zero? # true
- そのクラスの継承関係を見るには
ancestors
メソッドを使う- クラスの家系図を確認するメソッド
- 継承関係上の祖先を辿ることができる
- 正確には、「親クラスと
include
しているモジュールを表示する」メソッド
p String.ancestors # [String, Comparable, Object, Kernel, BasicObject]
p Integer.ancestors # [Integer, Numeric, Comparable, Object, Kernel, BasicObject]
p Float.ancestors # [Float, Numeric, Comparable, Object, Kernel, BasicObject]
p Array.ancestors # [Array, Enumerable, Object, Kernel, BasicObject]
class Parent
end
class Child < Parent
end
p Parent.ancestors # [Parent, Object, Kernel, BasicObject]
p Child.ancestors # [Child, Parent, Object, Kernel, BasicObject]
- どのクラスの祖先にも
Object, Kernel, BasicObject
がある- これらのクラスやモジュールによって、オブジェクトとしての基礎となる動作が提供されている
親子クラスで同名のメソッドが存在する場合の挙動
class Item
def name
@name
end
def name=(text)
@name = text
end
def full_name
@name
end
end
class Drink < Item
def size
@size
end
def size=(text)
@size = text
end
def full_name
"#{@name} : #{@size}"
end
end
item = Item.new
drink = Drink.new
item.name = "apple"
drink.name = "coffee"
drink.size = "small"
p item.full_name # "apple"
p drink.full_name # "coffee : small"
- 親子クラスで同名のメソッドが存在する場合、自分のクラスのメソッドが呼ばれる
- 正確には、継承関係を上流へ辿っていき、最初に該当したメソッドを呼び出す
- 親クラスの同名メソッドは呼ばれない
親クラスのメソッドを呼び出す super
- 上記の例は「親クラスの同名メソッドは呼ばれない」だけであり、上書きしている訳ではない
- 子クラスの中で親クラスのメソッドを呼び出す場合
- メソッドの中で
super
と記述する
- メソッドの中で
class Item
def name
@name
end
def name=(text)
@name = text
end
def full_name
@name
end
end
class Drink < Item
def size
@size
end
def size=(text)
@size = text
end
def full_name
super #
end
end
drink = Drink.new
drink.name = "coffee"
drink.size = "small"
p drink.full_name # "coffee"
- Drink クラスの
full_name
メソッドで、Item クラスのfull_name
メソッドを呼び出している super
を実行すると、親クラスの同名メソッドが呼び出され、戻り値として返す