Menu
Coddy logo textTech

メソッドのオーバーライド

CoddyのRubyジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 23/57。

サブクラスは、同じ名前のメソッドを定義することでメソッドをオーバーライドできます。Rubyはまずオブジェクト自身のクラスでメソッドを探し、その後でスーパークラスを探すため、サブクラスのバージョンが優先されます:

class Animal
  def speak
    "..."
  end
end

class Dog < Animal
  def speak
    "Woof"
  end
end

class Fish < Animal
end

puts Dog.new.speak
puts Fish.new.speak

出力:

Woof
...

スーパークラスのメソッドが別のメソッドを呼び出す場合、サブクラスのオブジェクトに対してはオーバーライドされたバージョンが使用されます。共有されるメソッドは一度だけ記述し、各サブクラスでは異なる部分だけを変更します。

class Animal
  def initialize(name)
    @name = name
  end

  def introduce
    "#{@name} says #{speak}"
  end

  def speak
    "..."
  end
end

class Cat < Animal
  def speak
    "Meow"
  end
end

puts Cat.new("Tom").introduce
puts Animal.new("Thing").introduce

出力:

Tom says Meow
Thing says ...

サブクラスで to_s をオーバーライドすると、そのサブクラスだけの表示方法が変わります。オーバーライドしていないメソッドは、引き続きスーパークラスから継承されます。

class Item
  def initialize(name, price)
    @name = name
    @price = price
  end

  def to_s
    format("%s %.2f", @name, @price)
  end
end

class SaleItem < Item
  def to_s
    format("%s %.2f (sale)", @name, @price * 0.8)
  end
end

puts Item.new("Lamp", 20)
puts SaleItem.new("Lamp", 20)

出力:

Lamp 20.00
Lamp 16.00 (sale)

Ruby が検索する順序は、クラスの祖先です。つまり、クラス自体、その後にスーパークラスが続き、Object まで検索されます。そのリストでメソッドを定義している最初のクラスが、そのメソッドを提供します。

class Animal
  def speak
    "..."
  end
end

class Dog < Animal
  def speak
    "Woof"
  end
end

class Puppy < Dog
end

puts Puppy.new.speak
p Puppy.ancestors.take(3)

出力:

Woof
[Puppy, Dog, Animal]
challenge icon

チャレンジ

簡単

給与計算のクラスを完成させてください。Employeeはnameを保持し、hours * 20を返すpay(hours)と、payを使用してAda: 800を返すpayslip(hours)を持ちます。Managerはpayをオーバーライドし、勤務時間にかかわらず固定値1500を返します。Internはpayをオーバーライドし、hours * 12を返しますが、最大300までです。payslipはEmployeeでのみ定義されています。

提供されたコードは、employee Ada 40、manager Bo 50、またはintern Cy 20の行を読み込み、対応するオブジェクトを作成して給与明細を出力し、その後に合計給与を出力します。

コードはemployee.rb、manager.rb、intern.rbに記述します。main.rbには提供された入出力コードが含まれており、編集できません。

自分で試してみよう

require_relative 'employee'
require_relative 'manager'
require_relative 'intern'

# 提供された入出力コード: そのままにしておく
input = []
while (line = gets)
  input << line.chomp
end
kinds = { "employee" => Employee, "manager" => Manager, "intern" => Intern }
total = 0
input.each do |line|
  kind, name, hours = line.split
  worker = kinds[kind].new(name)
  puts worker.payslip(hours.to_i)
  total += worker.pay(hours.to_i)
end
puts "total: #{total}"
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Rubyオンラインコンパイラ