継承はオブジェクト指向プログラミングの重要な概念で、既存のクラス(親クラス)の機能を引き継いで新しいクラス(子クラス)を作成する仕組みです。共通する機能を親クラスにまとめ、差分だけを子クラスで定義することで、コードの重複を減らせます。Rubyでは<記号を使って継承関係を定義します。
基本的な使い方
Ruby
# 親クラス
class Animal
attr_reader :name
def initialize(name)
@name = name
end
def speak
puts "#{@name}が鳴いています"
end
def info
puts "動物: #{@name}"
end
end
# 子クラス
class Dog < Animal
def speak
puts "#{@name}: ワンワン!"
end
end
class Cat < Animal
def speak
puts "#{@name}: ニャー!"
end
end
dog = Dog.new('ポチ')
cat = Cat.new('タマ')
dog.speak # オーバーライドされたメソッド
cat.speak
dog.info # 親クラスから継承したメソッド
cat.info実行結果
ポチ: ワンワン!
タマ: ニャー!
動物: ポチ
動物: タマclass Dog < AnimalでDogがAnimalを継承しています。DogはAnimalのinitializeとinfoメソッドをそのまま使えます。speakメソッドは子クラスで再定義(オーバーライド)されているため、子クラス独自の動作をします。
superで親クラスのメソッドを呼ぶ
superを使うと、オーバーライドしたメソッド内から親クラスの同名メソッドを呼び出せます。
Ruby
class Vehicle
attr_reader :name, :speed
def initialize(name, speed)
@name = name
@speed = speed
end
def info
"#{@name}(速度: #{@speed}km/h)"
end
end
class Car < Vehicle
def initialize(name, speed, seats)
super(name, speed) # 親クラスのinitializeを呼ぶ
@seats = seats
end
def info
super + "(座席数: #{@seats})" # 親クラスのinfoを呼んで拡張
end
end
class Bicycle < Vehicle
def initialize(name)
super(name, 20) # 速度は固定で親クラスに渡す
end
end
car = Car.new('セダン', 180, 5)
bike = Bicycle.new('ロードバイク')
puts car.info
puts bike.info実行結果
セダン(速度: 180km/h)(座席数: 5)
ロードバイク(速度: 20km/h)super(name, speed)で親クラスのinitializeに引数を渡しています。superを引数なしで呼ぶと、現在のメソッドと同じ引数が自動的に親メソッドに渡されます。
is_a?で型チェック
Ruby
class Animal; end
class Dog < Animal; end
class Cat < Animal; end
dog = Dog.new
puts dog.is_a?(Dog) # true
puts dog.is_a?(Animal) # true(親クラスも含む)
puts dog.is_a?(Cat) # false
puts dog.class # Dog実行結果
true
true
false
Dog実践的な使い方
Ruby
class Shape
attr_reader :color
def initialize(color = '黒')
@color = color
end
def area
0 # サブクラスでオーバーライドする
end
def to_s
"#{self.class.name}(色: #{@color}、面積: #{area})"
end
end
class Circle < Shape
def initialize(radius, color = '黒')
super(color)
@radius = radius
end
def area
(3.14159 * @radius ** 2).round(2)
end
end
class Rectangle < Shape
def initialize(width, height, color = '黒')
super(color)
@width = width
@height = height
end
def area
@width * @height
end
end
shapes = [
Circle.new(5, '赤'),
Rectangle.new(10, 6, '青'),
Circle.new(3),
Rectangle.new(4, 4, '緑')
]
shapes.each { |s| puts s }
puts "---"
total = shapes.sum(&:area)
puts "合計面積: #{total.round(2)}"実行結果
Circle(色: 赤、面積: 78.54)
Rectangle(色: 青、面積: 60)
Circle(色: 黒、面積: 28.27)
Rectangle(色: 緑、面積: 16)
---
合計面積: 182.81Rubyは単一継承
Rubyでは1つのクラスは1つの親クラスのみ継承できます(単一継承)。複数の機能を組み合わせたい場合はモジュールのinclude(Mixin)を使います。これにより多重継承の問題を避けつつ、柔軟な機能拡張が可能です。
継承の深さに注意
継承階層が深くなりすぎると、コードの理解やデバッグが困難になります。一般的に3階層以上の継承は避け、コンポジション(クラスを組み合わせる方法)を検討しましょう。「is-a」(〜である)関係のときに継承を使うのが適切です。
まとめ
class 子クラス < 親クラスで継承関係を定義する- 子クラスは親クラスのメソッドをすべて引き継ぐ
- 子クラスで同名メソッドを定義するとオーバーライドになる
superで親クラスのメソッドを呼び出せる- Rubyは単一継承で、多重継承にはモジュールを使う