Rubyの継承チェーンについて勉強したのでメモです。
継承チェーンとは?
Rubyのクラスのスーパークラスを見る、そのスーパークラスのスーパークラスを見る、をBasicObjectが見つかるまで続ける。
このクラスの道筋が継承チェーンとなります。
Stringクラスの場合だと以下のようになります。
irb(main):001:0> String.superclass => Object irb(main):002:0> Object.superclass => BasicObject irb(main):003:0>
StringクラスのスーパークラスがObjectクラス、ObjectクラスのスーパークラスがBasicObjectクラスとなっています。
ちなみにBasicObjectクラスを見ると
irb(main):003:0> BasicObject.superclass => nil
となっているので、BasicObjectクラスが終点であることがわかります。
継承チェーンのモジュールについて
しかしここでクラスの親クラスを返すancestorsメソッドを使用して見ると
irb(main):004:0> String.ancestors => [String, Comparable, Object, Kernel, BasicObject]
先ほどスーパークラスで辿った時に出てこなかった「Comparable」と「Kernel」があります。
これらは、クラスではなくモジュールとなります。
モジュールはクラスにインクルードされることで、クラスの継承チェーンに挿入されます。
それではインクルードした場合、継承チェーンのどこに挿入されるのでしょうか?
またインクルードする順番は関係するのでしょうか?
試してみましょう。
module A end module B end class C include A include B end p C.ancestors
実行結果は
[C, B, A, Object, Kernel, BasicObject]
まず自作クラスのスーパークラスはデフォルトでObjectクラスになるのですが、
インクルードされたModuleがスーパークラスの前に差し込まれています。
またBの方がAより先に来ています、
つまりインクルードすると、
・自分のクラスの後に差し込まれる
・複数インクルードすると後に指定した方が継承チェーンでは先に来る
となります。
ちなみに
module A end module B end class C prepend A #includeをprependに変更 include B end p C.ancestors
とincludeをprependに変更すると、自分のクラスの後ではなく先に挿入されます。
以下実行結果です
[A, C, B, Object, Kernel, BasicObject]
Cより先にAが来ていますね。
このようにインクルードする順番は、includeを使うかprependを使うか、
includeの場合は、上に書くか下に書くかで変わって来ます。
モジュールをインクルードしてメソッドを書き変える場合などに意識するようにしようと思います。
参考にした文書は以下になります。