Ruby TIPS
クラスのメソッドをオーバーライドするには?
継承先クラスの新メソッドで元クラスの既存メソッドをオーバーライドして異なる機能に置き換える方法と、新メソッド内から既存メソッドを呼び出すことで既存機能に新機能を追加する方法を説明する。
サブクラスでメソッドをオーバーライドすれば、スーパークラスの機能と同じ名前で、異なる機能を持つメソッドを作成したり、スーパークラスのメソッドに機能を追加したメソッドを作成したりできる。今回はメソッドをオーバーライドする方法を見る。
メソッドをオーバーライドする
オーバーライドとは、スーパークラスのメソッドを「再定義」することと考えればよい。従って、オーバーライドされたメソッドには同じ名前が使われる。では、サブクラスの作成とメソッドのオーバーライドを具体的な例で見ていこう。
例えば、猫を表すCat
クラスがあり、そのクラスを継承したTiger
クラスを作成したものとする。Tiger
クラスはもちろん「虎」を表すクラスである。虎はネコ科なので猫の性質や働きを受け継いでいるというわけである。
ここからは順を追って見ていくので、オーバーライドは少しだけ後回しにして、まずは、単にクラスを継承しただけのコードを書いてみよう。
class Cat
def meow
return "にゃあ"
end
end
class Tiger < Cat
end
animal = Tiger.new
puts animal.meow
|
ここでは、コードを簡単にするために余計な機能は全て省いてある。Cat
クラスで定義されているmeow
メソッドは猫の鳴き声の「にゃあ」という文字列を返す。一方、Cat
クラスのサブクラスであるTiger
クラスには、何もメソッドを定義していない。最後に、Tiger
クラスのインスタンスを作成し、meow
メソッドを呼び出している。
Tiger
クラスは単にCat
クラスを継承しただけで、新しい機能は全く追加していない。つまり、Tiger
クラスには、meow
メソッドは書かれていない。この場合、Tiger
クラスのmeow
メソッドを呼び出すと、スーパークラスで定義されているmeow
メソッドが呼び出される。実行例は以下の通り。
$ ruby sample001.rb
にゃあ
$
|
Tiger
クラスのmeow
メソッドを呼び出したが、Tiger
クラスにはmeow
メソッドが定義されていないので、スーパークラスのmeow
メソッドが呼び出され、「にゃあ」と表示された。
サブクラスで定義していないメソッドを呼び出したとき、スーパークラスに同じ名前のメソッドがあれば、スーパークラスのメソッドが呼び出される。ところが、サブクラスでちょっと違った機能を提供したり、機能を追加したりしたいことがある。例えば、同じ鳴き声といっても、猫は「にゃあ」と鳴き、虎は「がおー」と吠える。そこで、Tiger
クラスではmeow
メソッドが「がおー」という文字列を返すようにしよう。
ここで、オーバーライドを利用する。これにはリスト1.2のように、単にサブクラスで同じ名前のメソッドを定義すればよい。
class Cat
def meow
return "にゃあ"
end
end
class Tiger < Cat
def meow
return "がおー"
end
end
animal = Tiger.new
puts animal.meow
|
Cat
クラスのmeow
メソッドは「にゃあ」という文字列を返し、そのサブクラスであるTiger
クラスのmeow
メソッドは「がおー」という文字列を返す。
実行例は以下の通り。
$ ruby sample002.rb
がおー
$
|
単に「がおー」と表示されるだけであるが、Tiger
クラスのmeow
メソッドが呼び出されていることが分かる。
ところで、場合によっては虎も「猫なで声」を出すこともあるかもしれない。そこで、必要に応じてスーパークラスのmeow
メソッドも呼び出せるようにしよう。
スーパークラスのメソッドはsuper
と書くだけで呼び出せる。その場合、スーパークラスのメソッドには、同じ引数が渡されることに注意。スーパークラスのメソッドを引数なしで呼び出したいときには、super()
のように()
を付ける必要がある。
class Cat
def meow
return "にゃあ"
end
end
class Tiger < Cat
def meow(flg)
if flg
return "がおー"
else
return super()
end
end
end
animal = Tiger.new
puts animal.meow(true)
puts animal.meow(false)
|
meow
メソッドの仮引数flg
に渡される値がtrueであれば「がおー」という文字列が返され、falseであれば、スーパークラスのmeow
メソッドが呼び出される。super
に()
を付けているので、引数なしでスーパークラスのmeow
メソッドが呼び出させる。
実行例は以下の通り。最初に「がおー」と表示され、次に「にゃあ」と表示される。
$ ruby sample003.rb
がおー
にゃあ
$
|
meow
メソッドの引数にfalseを指定するとスーパークラスのmeow
メソッドが呼び出されるので、「にゃあ」と表示される。
ここで、試しにsuper
の後の()
を削除して実行してみよう(ファイル名は「sample004.rb」とする)。その場合、サブクラスのmeow
メソッドに指定した引数がそのままスーパークラスのmeow
メソッドに渡される。しかし、スーパークラスのmeow
メソッドは引数のないメソッドなのでエラーとなる(実行例1.4)。
$ ruby sample004.rb
がおー
sample004.rb:3:in `meow': wrong number of arguments (1 for 0) (ArgumentError)
from sample004.rb:13:in `meow'
from sample004.rb:20:in `<main>'
$
|
この例では、スーパークラスのmeow
メソッドは引数を取らない。サブクラスのmeow
メソッドの引数をそのままスーパークラスのmeow
メソッドに渡そうとするので、「引数の個数が異なる」というエラーが表示される。
逆に、スーパークラスのメソッドとオーバーライドされたメソッドが同じ引数を取るのであれば、super
の後に()
を付けてしまうとエラーになる。ただし、スーバークラスのメソッドで引数が省略可能であれば、super()
としてもエラーにはならない。
ここで見た例では、オーバーライドしたメソッドでスーパークラスと異なる機能を提供しているが、スーパークラスの機能に何らかの機能を追加するためにメソッドをオーバーライドする場合も多い。そのような場合には、オーバーライドしたメソッドの定義の中で、最初にsuper
を呼び出してスーパークラスの機能を実行するようにし、それに引き続きサブクラス独自の処理を記述するとよい。あまり意味のない例ではあるが、簡単なコードで働きを見ておこう(リスト1.4、実行例1.5)。
class Cat
def introduce
puts "猫です"
end
end
class Tiger < Cat
def introduce
super
puts "虎でもあります"
end
end
animal = Tiger.new
animal.introduce
|
Cat
クラスのintroduce
メソッドでは「猫です」と表示する。Tiger
クラスのintroduce
メソッドでは、まずスーパークラスのintroduce
メソッドを呼び出し、その後「虎でもあります」と表示する。
$ ruby sample005.rb
猫です
虎でもあります
$
|
「猫です」はスーパークラスのintroduce
メソッドによって表示されたもので、「虎でもあります」はサブクラスのintroduce
メソッドの中に記述されたputs
メソッドによって表示されたものである。
今回はメソッドをオーバーライドする方法と、スーパークラスのメソッドを呼び出す方法を紹介した。特に、super
に()
を付けないと引数がそのままスーパークラスのメソッドに渡されることと、super
に()
を付けるとスーパークラスのメソッドが引数なしで呼び出されることに注意しよう。
まとめ
メソッドをオーバーライドすれば、同じ名前のメソッドで、スーパークラスのメソッドとは異なる機能をサブクラスで提供したり、スーパークラスのメソッドにサブクラスで機能を追加したりできる。super
を使えばオーバーライドされたメソッドからスーパークラスのメソッドが呼び出せる。
処理対象:オーバーライド カテゴリ:文法 > クラス
※以下では、本稿の前後を合わせて5回分(第12回~第16回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
12. クラスとそのコンストラクター/アクセサー/メソッドを定義し利用するには?
Rubyプログラミングの基本中の基本として、クラスの定義から、そのインスタンスの作成・利用、インスタンスメソッドの定義、変数へのアクセスまでを説明する。
13. クラスを継承するには? メソッドの呼び出しをprivate/protectedで制限するには?
オブジェクト指向言語の特長である「クラスの継承」をRubyで実現する方法を解説。スーパークラスのメソッドの呼び出し制限で、Ruby言語特有の内容についても紹介する。
14. 【現在、表示中】≫ クラスのメソッドをオーバーライドするには?
継承先クラスの新メソッドで元クラスの既存メソッドをオーバーライドして異なる機能に置き換える方法と、新メソッド内から既存メソッドを呼び出すことで既存機能に新機能を追加する方法を説明する。
16. RSSを扱うには? ― 標準rssライブラリ利用して天気予報を表示する
Rubyに標準搭載されているrssライブラリを使って、Webサイトで提供されているRSS/Atomフィードを処理する方法を説明する。例として天気予報情報のRSSフィードを使う。