Help us understand the problem. What is going on with this article?

自作クラスの親クラスはModuleでもClassでもなくObjectである

More than 3 years have passed since last update.

自作クラスの親クラスがModuleでもClassでもなくObjectであることが不思議に思えたので、Object, Module, Classの影響を調べてみました。これら3つの関係は下の通りです。

14541f2e9517ce75a743d0e2336a2df3.jpg

ee5171ef485420058b7f3b582dd397ac.jpg

上記3クラスを拡張した場合、互いにどう影響するのでしょうか。

class Object
  def self.object_class_method
    "object class method"
  end

  def object_instance_method
    "object instance method"
  end
end

class Module
  def self.module_class_method
    "module class method"
  end

  def module_instance_method
    "module instance method"
  end
end

class Class
  def self.class_class_method
    "class class method"
  end

  def class_instance_method
    "class instance method"
  end
end

拡張したメソッドが、各クラス、そのインスタンスから呼び出せるか表にまとめました。赤いマルとバツは自分が気になった部分です。

ruby-class.002.jpeg

この結果からわかったことを記述していきます。

Classクラスのインスタンスメソッドは全てのクラスメソッド

Object.object_instance_method
Object.module_instance_method
Object.class_instance_method

Object, Moduleのインスタンスメソッドは子孫クラスのClassに引き継がれます。Classのインスタンスは他のクラスになり、全てのクラスでobject_instance_method, module_instance_methodが使えるようになります。class_instance_methodが使える理由も同じです。

インスタンスメソッドが他のクラスのクラスメソッドになるのは、Classクラスのインスタンスが他のクラスになるからです。

Foo = Class.new
# Class.new != Foo.new
Module.object_instance_method
Module.module_instance_method
Module.class_instance_method

Moduleもクラスなので上記と同じ理由でClassのインスタンスメソッドをクラスメソッドとして呼び出すことが出来ます。

Class.object_instance_method
Class.module_instance_method
Class.class_instance_method

こちらが少しややこしいです。全てのクラスはClassから出来ています。Classもクラスなので、Class.newと同じメソッドを持っていることになります。

Class.classClassが得られることで、自分で自分自身を定義していることが分かります。

Classのインスタンスメソッドは他のクラスのインスタンスから呼び出せない

# 下記のメソッド呼び出しは`new`以外はエラーになります
object = Object.new
object.module_instance_method
object.class_instance_method

foo = Foo.new
foo.module_instance_method
foo.class_instance_method

このため、Classのインスタンスメソッドは他のクラスのインスタンスから呼び出す事ができません。Classクラスのインスタンス、つまりクラスからのみ呼び出すことが出来ます。

Classクラスのクラスメソッドは、他のクラスに受け継がれない。

Foo = Class.new
Foo.object_class_method


# 下記のメソッド呼び出しはエラー
Foo.module_class_method
Foo.class_class_method

クラスは親クラスを指定しない場合は、勝手にObjectクラスが親となります。なのでObjectクラスのクラスメソッドが使えます。

Moduleクラスのクラスメソッドは、その子クラスのClassクラスのクラスメソッドとなります。クラスメソッドなのでClass.newでは使えません。Class.newはクラスであることは先述のとおりです。つまり、Classクラスのインスタンスメソッドは他のクラスに影響しますが、クラスメソッドは影響しません。影響するクラスメソッドは継承したクラスのものです。

自作クラスの親クラスは、ModuleでもClassでもなくObjectである。

自作クラスの親クラスがObjectになるのが不思議でした。ModuleClassに追加したインスタンスメソッドが自作クラスにも影響がありますよね。これはModuleClassを継承しているからなのでは?と思いましたが違いました。その理由は下記のとおりです。

  • Classのインスタンスメソッドが、自作クラスのクラスメソッドになる。
  • 継承した場合は親のクラスメソッドは、子のクラスメソッドになる。

Classクラスが自作クラスに影響があるのは、継承ではなくクラス自体の仕様を変えているからです。上記2点のせいで少し勘違いをしてしまいました。

togetter
トゥギャッターとインドネシア版のChirpstory、あと独自のサービス&ツールを日々開発している
http://togetter.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away