アプリ版:「スタンプのみでお礼する」機能のリリースについて

Rubyのクラスの継承関係について質問です。

RubyではすべてのクラスはObjectクラスが親クラスとなっていると思います。
そこで
p File.class;
と記述して実行すると

FileクラスがClassクラスとして表示されます。

FileはFileクラスのはずなのになぜClassクラスなのでしょうか?

そして最上位のクラスであるObjectクラスも
p Object.class;
とすると
Classクラスと出力されてしまいます。

なぜなのでしょうか???

p Class.class;
と記述するとClassクラスと出力されました。

もうわけがわかりません。
どなたかご教授ください。お願いします。本気でド壷中です。

A 回答 (10件)

No3,6,9です(なぜか3の倍数の回答が私だ)。



>ClassクラスのインスタンスなのにFileという定義されたクラスであると・・・。
>おもえばここの解釈が一番の原因でしたね。いまでもちょっと捕らえにくいのですが。

Rubyではほとんどのものがオブジェクト(主要な要素でオブジェクトでないのはメソッドくらい?)と、あちこちで書かれています。1 や nil がオブジェクトであり、クラスもオブジェクトですね。

最後に、クラスメソッドと特異メソッドとの関係について。
クラスでないオブジェクトの特異メソッドについては、わかると思うので説明略。

>ただ実際はクラスメソッドの定義の仕方と特異メソッドの定義の仕方がことなるので厳密には違うものなのでしょうか?

定義の仕方は同じです。というか、クラスメソッドの定義の仕方は、特異メソッドの定義の仕方の一種。

また、
とあるクラスFooのクラスメソッド = Foo の特異メソッド + Fooの祖先クラスのどれかの特異メソッド

なので、「hogeはFooのクラスメソッドである」と「hogeはFooの特異メソッドである」は等しくないです。



アドバイスとしては、考えるときに、「Fileオブジェクト」とか、「Fileインスタンス」という言葉を使わない方がいいです。
「Fileクラスのオブジェクト(インスタンス)」と「Classクラスのオブジェクト(インスタンス)であるFile」とが、意識下で混同されてしまっていると思います。いざ明示的に聞かれると違うことはおわかりのようですが、曖昧な言葉で思考しているとつい引きずられてしまいます。
    • good
    • 0

>その「instance_methods(true)」というメソッドによって返ってくる戻り値は受け取り側であるレシーバ・・・すなわちFileインスタンスというClassクラスのインスタンスが持つメンバメソッドを返すということでは?



これは違いますね。Fileというインスタンスの持つメソッドを得るのは、File.methods です。
File.instance_methods は、File自身じゃなくて「Fileクラスに属するインスタンスの持つメソッド一覧」です。
File自体はFileクラスのインスタンスではありませんので。

Classクラスでインスタンスメソッドとして定義されているものと、Fileクラスでインスタンスメソッドとして定義されているものは異なるので、結果が異なって当然です。StringクラスのインスタンスメソッドとFixnumクラスのインスタンスメソッドが異なるのと同じ理屈。

次に進むと、
Classというインスタンスの持つメソッド = Class.methods の結果と Fileというインスタンスの持つメソッド = File.methods の結果も違います。
Class.methods => Classクラスのインスタンスが(共通で)持つメソッド + Classのクラスメソッド
File.methods => Classクラスのインスタンスが(共通で)持つメソッド + Fileのクラスメソッド

「Classクラスのインスタンスが(共通で)持つメソッド」は、要は Class.instance_methods で得られるものです。
class Class
 def foo
 end
end
のfooのようなものですね。

「Fileのクラスメソッド」は、
class File
 def self.hoge
 end
end
のhogeのようなものですね。Javaだとスタティックメソッドと言います。
Rubyだと、クラスメソッドは、そのクラスの特異メソッドとして実現されています。

この回答への補足

ありがとうございます。

ようやくある程度理解できた気がします。
いままでお答え下さったかたがたのお話を要約してまとめてみます。

例のごとくClassクラスのインスタンスであるFileクラスですが、これは再三皆さんがおっしゃったとおりClassクラスのインスタンスですね。
File.class という式とclassというメソッド(レシーバの属するクラスを返す)から確認できます。しかしながらClassクラスのインスタンスであるが、れっきとしたクラスであると・・・。ClassクラスのインスタンスなのにFileという定義されたクラスであると・・・。
おもえばここの解釈が一番の原因でしたね。いまでもちょっと捕らえにくいのですが。
でなんどもでてきたinstance_methodsですが、これはちょっとびっくりしました。instance_methodsはそもそもModuleクラスで定義されているメンバメソッド(インスタンスメソッドっていうの嫌いなんですごめんなさい)ですよね?
なのにModule.instance_methodsなっていうアクセスができる・・・・。これメンバメソッドとして定義されているのになんでクラスメソッドとして定義できるんや!!!ってまた深い谷底に落ちかけたそのときに気づきました。ModuleもClassクラスから作成されたインスタンスなんですよね?
でさらにClassクラスの親クラスってModuleクラスであるのでModuleクラスのメンバメソッドを継承していると・・・。であらゆるクラスCGIやFileなどは、Classクラスのインスタンスだからそのinstance_methodsへとアクセスができると。(どうもみためからクラスメソッドにアクセスしているようにみえますよね。)で、いよいよClassクラスのインスタンスであるFileクラスですが、これにはopenメソッドやnewメソッド、unlikメソッドなどの特異メソッド・・・つまりクラスメソッドが定義されていると。ただ実際はクラスメソッドの定義の仕方と特異メソッドの定義の仕方がことなるので厳密には違うものなのでしょうか?
どちらにせよアクセスはJAVA PHPといった言語のクラスメソッドと同じものなのでここはあきらめてそう思うことにします。
で上記のことからFileクラスというのは特異クラスとして定義されたFileオブジェクトであると・・。ここもちょっと捕らえにくいですが、そういうものだとしてあきらめます。

まだちょっとあやしいところもありますが、なんとか前に進めそうです。
一番厄介なのはClassクラスのインスタンスの癖にちゃんとしたクラスとして定義されているってところでしょうか・・・。

補足日時:2011/08/18 22:59
    • good
    • 0

Rubyの内部に詳しくなりそうなので、お金の余裕ができれば私も「メタプログラミングRuby」を購入したいですね。



No.5での補足の通り(以下引用)、Fileクラス(とそれが継承するクラス)の特異メソッドですね。

>p File.instance_methods(true);で出力されており尚且つ
>p Class.instance_methods(true);で出力されないメソッドすべてが特異メソッドという
>解釈でいいのでしょうか?

以下についていは、

>Rubyで存在するインスタンスにはすべて特異メソッドなるメソッドが
>存在するということでしょうか?

意図的に作れば存在するということです。
以下のコードを参照してください。

class Foo
end

foo1 = Foo.new
foo2 = Foo.new

# foo1の特異メソッドを定義
def foo1.eigen_method
puts "eigen_method"
end

foo1.eigen_method # => eigen_method
foo2.eigen_method # => エラー

# Fooの特異メソッドを定義
def Foo.class_method
puts "class_method"
end

Foo.class_method # => class_method
Class.class_method # => エラー
    • good
    • 0

#6の補足へ



>すなわちFileインスタンスというClassクラスのインスタンス

Fileインスタンスというのは、File.newの結果出てくるものだと思ってください。「File」そのものとは違います。

そのため

>その「instance_methods(true)」というメソッドによって返ってくる戻り値は受け取り側であるレシーバ・・・すなわちFileインスタンスというClassクラスのインスタンスが持つメンバメソッドを返すということでは?

ここへの回答が導きだされます。

「FileインスタンスというClassクラスのインスタンス」

ではなく

「「ClassクラスのインスタンスであるFileクラス」のインスタンスがFileインスタンス」なので、ClassクラスのインスタンスとFileインスタンスは異なるインスタンスメソッドを返します。

>この時点でのFileというキーワードは、Classクラスによって生成されたClassインスタンスという認識でいいですよね?

あってます。

>それであればinstance_methods(true);はClassクラスに定義されたメソッドのみを返すのに

instance_methodsは、自分から作られたインスタンスが持つメソッドを返します。(ここではFile.new)
なので、Classクラスに定義されたメソッドだけを返すケースのほうが稀です。(File.newとClass.newは異なりますよね?という)
    • good
    • 0

>Fileインスタンスは、Classクラスのインスタンスですよね。



Fileインスタンスとは?
(A)Fileクラスのインスタンスのことですか?
(B)ClassクラスのインスタンスであるFileのことですか?

Bならその通りです。Aなら当然違います。

>(p File.class;で出力っするとClassクラスと返ります。)

これは File は Classクラスのインスタンスだと言うことです。

>p File.instance_methods(true);

これはFileクラスに属するインスタンスが持つメソッドの一覧です。

>p Class.instance_methods(true);

これはClassクラスに属するインスタンスが持つメソッドの一覧です。

FileクラスとClassクラスは違うものなので、当然内容が違います。

クラスとインスタンスの区別がついていないものと思います。

Class => Class という名前のクラス自体を表す。これはClassクラスのインスタンス
File => Fileという名前のクラス自体を表す。これはClassクラスのインスタンス
class Foo; end => Foo という名前のクラスを定義する。FooはClassクラスのインスタンス
File.new("hoge") => hoge という名前のファイルに関連付いたFileクラスのインスタンスを生成する。これはFileクラスのインスタンス

この回答への補足

>(p File.class;で出力っするとClassクラスと返ります。)

これは File は Classクラスのインスタンスだと言うことです。

>p File.instance_methods(true);

これはFileクラスに属するインスタンスが持つメソッドの一覧です。
上記箇所がちょっとあやしいですね・・・。
お話のとおり「File」とはClassクラスのインスタンスというのはわかります。

その「instance_methods(true)」というメソッドによって返ってくる戻り値は受け取り側であるレシーバ・・・すなわちFileインスタンスというClassクラスのインスタンスが持つメンバメソッドを返すということでは?

>p File.instance_methods(true);
この時点でのFileというキーワードは、Classクラスによって生成されたClassインスタンスという認識でいいですよね?
それであればinstance_methods(true);はClassクラスに定義されたメソッドのみを返すのに
なぜ

>p File.instance_methods(true);と

>p Class.instance_methods(true);では返ってくる値が違うのかなとおもったのです。

補足日時:2011/08/18 06:59
    • good
    • 0

あー。

誤魔化しがあったのでちょっと補足。

普通のクラス Foo であれば、そのインスタンス foo, bar が応答するメソッドは同じだと感じますね。
foo.hello() が有効なら、bar.hello() も有効だろう。と。

でも File インスタンスは File.basename("/usr/local/bin/ruby") に応答するけど、もちろん Class.basename("/usr/local/bin/ruby") はエラーになります。

それが特異メソッドです。

普通のクラス Foo でも実際には foo.fly() は有効だけど、bar.fly() はエラーになるようなメソッドを定義することができます。

この回答への補足

HashインスタンスやArrayインスタンス、CGIインスタンスなどすべての
インスタンスはClassクラスからつくられたインスタンスであり、各インスタンスが持つメンバメソッドやメンバ変数すべて同一のはずです。
通常 JAVAやPHPなどのオブジェクト指向ではそうだと思います。

上記のお話からだとRubyで存在するインスタンスにはすべて特異メソッドなるメソッドが
存在するということでしょうか?

p Class.class;
p Class.instance_methods(true);

p File.class;
p File.instance_methods(true);

上記のように、p File.instance_methods(true);で出力されており尚且つ
p Class.instance_methods(true);で出力されないメソッドすべてが特異メソッドという
解釈でいいのでしょうか?

補足日時:2011/08/18 07:23
    • good
    • 0

> 同じClassクラスから作成されたであろうインスタンスであればメソッドの類は同じはず


> だと思うのですが?
> なぜメソッドの数が異なるのでしょうか??


激しく混乱していますね。

普通のクラス例えば Foo があったとして、その別々のインスタンス foo, bar に対して
foo.hello() と bar.hello() の結果が違うとして、おかしいと思いますか?

instance_methods は Module クラスに定義されていて、そのレシーバが異なれば当然結果も違うでしょう。

この回答への補足

確かに、同じクラスから作成された個別のインスタンスであればそれぞれ個別のメンバ変数・メンバメソッドを持つことになるので

それぞれ別の値を持つと思いますが、(メソッドの引数によってはね)先ほどnotnotさんに補足した件ですが、

http://ref.xaio.jp/ruby/classes/module/instance_ …
から参照してきましたが
「instance_methodsメソッドは、クラスやモジュールで定義されているインスタンスメソッドの名前を集めて配列にして返します。配列に含まれるのはpublicなメソッドかprotectedなメソッドです。privateなメソッドは含まれません。」

とあります。
先ほど補足したように、 fooとbarは別々のインスタンスですが(しかしもともとはFooクラスという出所は同じ)持っているメンバメソッド、メンバ変数はまったく同じだと思うのです。そこで先ほどの、Classクラスのインスタンスである ClassインスタンスとFileインスタンスの持つメソッドは同じはずではということです。

補足日時:2011/08/18 00:22
    • good
    • 0

このレベルであれば、「メタプログラミング Ruby」を読むまでもなく普通の入門書でいいと思います。

というか、このレベルでつまづいているのなら、「メタプログラミング Ruby」は難しすぎると思います。
(Rubyをやるなら買っておいていずれ損はない本なので、とりあえず買ってみるのもいいかと)

>つまりは、FileやCGI、あるいは自作のクラスがClassクラスというのはつじつまあわせということですか・・・?

いいえ。

>このClassクラスってあらゆるインスタンスが所属するクラスになっていますが・・・・・・、

ちがいます。クラスだけが属するクラスです。

>実際は実態のないクラスというわけですか・・・?

実態はあります。

>たとえば、Fileというクラスインスタンス?(とでもいえばいいのか)はClassクラスのインスタンス(#p File.class)であり、

ここまでは合ってます。

>さらにFileクラスの親クラス(#p File.superclass)はIOクラスでもありますよね?

これも合ってます。

>さらにはIOクラスのクラスインスタンス?もClassクラスのインスタンスとなっていて・・・・・・。

これも合ってます。

>あれ?堂々巡りですか???

何が堂々巡りなのでしょうか?あるクラスの親クラスが何かと言うことと、クラスがClassクラスに属することは何の関係もありません。

>Classクラスはすべてのクラスのメンバ変数やメンバメソッドを継承したすべての各クラスの親クラスということですか?

上に書いたように、「A が Bクラスのインスタンスである」と、「Aクラス の親クラスが Cである」とは何の関係もありません。

>最上位のObjectクラスも(p Object.class)でClassクラスとして存在してますし・・。

クラスの継承による階層構造と、とあるインスタンスがあるクラスに属するという関係性とがごっちゃになっているようですね。
それらは全く独立した概念です。

この回答への補足

では、しつこいですが質問です。
Fileインスタンスは、Classクラスのインスタンスですよね。
上記より、これは大丈夫だと思います。

(p File.class;で出力っするとClassクラスと返ります。)

でこれでFileインスタンスが持っているメソッド一覧と

ClassクラスからつくられたClassインスタンスのメソッド一覧を
(p Class.class; で出力するとこれもClassクラスから作られたインスタンス)
それぞれ出力するとメソッドの数が異なります。

print "<hr />";
p File.class;
p File.instance_methods(true);
print "<hr />";
p Class.class;
p Class.instance_methods(true);

同じClassクラスから作成されたであろうインスタンスであればメソッドの類は同じはず
だと思うのですが?
なぜメソッドの数が異なるのでしょうか??

ご教授ねがいます 。

補足日時:2011/08/17 23:18
    • good
    • 0

自分もたまにこんがらがるんですが、個人的に重要だと思ってるのはこのへんです。



・クラス~インスタンスと、スーパークラス~サブクラスの関係は違う物
・インスタンスを作ったり、スーパークラスを持てるのは「Class(のサブクラス含む)のインスタンス」だけ
・すべてのオブジェクトは、何かのインスタンスである



・クラスは必ず必要だが、スーパークラスは無い時もある


・クラス~インスタンス:
「BasicObjectのクラスはClass」「ClassのクラスはClass」という循環構造になっている

・スーパークラス~サブクラス:
BasicObject(~1.8だとObject)を頂点とするツリー構造になっている。


これを踏まえると
>FileはFileクラスのはずなのになぜClassクラスなのでしょうか?

Fileは「File」という定数名がつけられた、Classクラスのインスタンスであり
File.openやらなんやらで作られるFileクラスのインスタンスとは別物である

ということになります。Objectもそうですね。

このへんは、#1さんも仰られているようにメタプログラミングRubyに詳しいので、自分もお勧めします。
あと、yuguiさんの初めてのRubyにも図解があった気がします。

<おまけ>
たまにこんがらがってきたら、こんな感じのものを書き殴って眺めるようにしてます。
http://ideone.com/f1WPp

これ以外にも「特異クラス」という厄介?な概念があるのですが・・・慣れるまで深追いしなくて良いと思ってます。
    • good
    • 0

この質問、継承関係とはまったく関係ありません。



class Foo
end

とした時、Foo は「クラス」

foo = Foo.new

とした時、foo は「インスタンス」ね。

んで、Foo は ruby の世界では「定数」でもあるんですわ。

BAR = 10

と書いたときの、BAR と似た感じで。

ということは、Foo は何かのクラスのインスタンスになっていないと辻褄があわないんですよ。
その「何か」が Class というクラスです。

試しに Foo = Class.new とかしても同じようにクラスが定義できるんです。

なんと、Class もやっぱり定数として ruby の世界に存在しているので、Class は Class のインスタンスになっているんです。


私の説明は下手なので「メタプログラミング Ruby」を買って読んで下さい。

この回答への補足

つまりは、FileやCGI、あるいは自作のクラスがClassクラスというのはつじつまあわせということですか・・・?

本を買ってよめという風におっしゃっているので詳細は書籍で確認しようとおもいますが、
このClassクラスってあらゆるインスタンスが所属するクラスになっていますが・・・・・・、実際は実態のないクラスというわけですか・・・?

たとえば、Fileというクラスインスタンス?(とでもいえばいいのか)はClassクラスのインスタンス(#p File.class)であり、さらにFileクラスの親クラス(#p File.superclass)
はIOクラスでもありますよね?さらにはIOクラスのクラスインスタンス?もClassクラスの
インスタンスとなっていて・・・・・・。
あれ?堂々巡りですか???


う~~ん・・・・・・。Classクラスはすべてのクラスのメンバ変数やメンバメソッドを継承したすべての各クラスの親クラスということですか?

あれ?。・・・・・・・・・わかりません。

最上位のObjectクラスも(p Object.class)でClassクラスとして存在してますし・・。

補足日時:2011/08/14 10:33
    • good
    • 0
この回答へのお礼

ありがとうございました。
とりあえずは、書籍でも見てみます。

お礼日時:2011/08/14 11:55

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!