Rubyのクラスの継承関係について質問です。
RubyではすべてのクラスはObjectクラスが親クラスとなっていると思います。
そこで
p File.class;
と記述して実行すると
FileクラスがClassクラスとして表示されます。
FileはFileクラスのはずなのになぜClassクラスなのでしょうか?
そして最上位のクラスであるObjectクラスも
p Object.class;
とすると
Classクラスと出力されてしまいます。
なぜなのでしょうか???
p Class.class;
と記述するとClassクラスと出力されました。
もうわけがわかりません。
どなたかご教授ください。お願いします。本気でド壷中です。
No.10ベストアンサー
- 回答日時:
No3,6,9です(なぜか3の倍数の回答が私だ)。
>ClassクラスのインスタンスなのにFileという定義されたクラスであると・・・。
>おもえばここの解釈が一番の原因でしたね。いまでもちょっと捕らえにくいのですが。
Rubyではほとんどのものがオブジェクト(主要な要素でオブジェクトでないのはメソッドくらい?)と、あちこちで書かれています。1 や nil がオブジェクトであり、クラスもオブジェクトですね。
最後に、クラスメソッドと特異メソッドとの関係について。
クラスでないオブジェクトの特異メソッドについては、わかると思うので説明略。
>ただ実際はクラスメソッドの定義の仕方と特異メソッドの定義の仕方がことなるので厳密には違うものなのでしょうか?
定義の仕方は同じです。というか、クラスメソッドの定義の仕方は、特異メソッドの定義の仕方の一種。
また、
とあるクラスFooのクラスメソッド = Foo の特異メソッド + Fooの祖先クラスのどれかの特異メソッド
なので、「hogeはFooのクラスメソッドである」と「hogeはFooの特異メソッドである」は等しくないです。
アドバイスとしては、考えるときに、「Fileオブジェクト」とか、「Fileインスタンス」という言葉を使わない方がいいです。
「Fileクラスのオブジェクト(インスタンス)」と「Classクラスのオブジェクト(インスタンス)であるFile」とが、意識下で混同されてしまっていると思います。いざ明示的に聞かれると違うことはおわかりのようですが、曖昧な言葉で思考しているとつい引きずられてしまいます。
No.9
- 回答日時:
>その「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クラスのインスタンスの癖にちゃんとしたクラスとして定義されているってところでしょうか・・・。
No.8
- 回答日時:
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 # => エラー
No.7
- 回答日時:
#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は異なりますよね?という)
No.6
- 回答日時:
>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);では返ってくる値が違うのかなとおもったのです。
No.5
- 回答日時:
あー。
誤魔化しがあったのでちょっと補足。普通のクラス 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);で出力されないメソッドすべてが特異メソッドという
解釈でいいのでしょうか?
No.4
- 回答日時:
> 同じ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インスタンスの持つメソッドは同じはずではということです。
No.3
- 回答日時:
このレベルであれば、「メタプログラミング 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クラスから作成されたであろうインスタンスであればメソッドの類は同じはず
だと思うのですが?
なぜメソッドの数が異なるのでしょうか??
ご教授ねがいます 。
No.2
- 回答日時:
自分もたまにこんがらがるんですが、個人的に重要だと思ってるのはこのへんです。
・クラス~インスタンスと、スーパークラス~サブクラスの関係は違う物
・インスタンスを作ったり、スーパークラスを持てるのは「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
これ以外にも「特異クラス」という厄介?な概念があるのですが・・・慣れるまで深追いしなくて良いと思ってます。
No.1
- 回答日時:
この質問、継承関係とはまったく関係ありません。
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クラスとして存在してますし・・。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java javaのクラスの分け方について質問です。 APIの内部用と外部用でクラスを分けたいのですがインター 2 2022/04/26 16:06
- 英語 分離不定詞 1 2023/07/16 17:29
- 英語 【 論・表 英訳 】 問題 次の文を英訳せよ。 クラスの誰もその質問に答えられませんでした。 解答 4 2022/07/25 21:43
- PHP アップロード画像数でCSSを分けることに成功したのですが、画像の横に文字を並べることが出来ません。 3 2023/07/28 17:16
- Java リレーションエンティティクラスとは何ですか? 2 2023/02/10 00:02
- JavaScript jQueryで同じクラス名のものを別物として扱いたい 1 2022/06/17 14:14
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
- Java java final 1 2022/06/10 22:49
- PHP アップロードファイルの数に応じてCSSを動的に変更したいのですが、方法がわかりません 3 2023/07/23 21:59
- JavaScript 指定したパスが現URLに含まれていたら特定要素を削除するJavascriptのコードを教えてください 2 2023/04/27 17:58
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
パソコンのスクリーンセーバー...
-
ビーリアルのユーザー名を変え...
-
100万件越えCSVから条件を満た...
-
(再質問)エクセルのマクロボ...
-
pandasでsqlite3にテーブル作成...
-
C言語の入力した文字を反転させ...
-
VBA
-
C++のCreateFile関数で、ASCII...
-
WinSCPで画像のように puttyを...
-
1、Rstudioで回帰直線を求める...
-
英数字を含む文字列(0-9,A-Z)...
-
7セグメント LED ディスプレイ ...
-
【メモリ不足で落ちる(python)】
-
Accessで文字列のバイト数読み込み
-
三項でたとえば交換って
-
Ruby on railsをrails sで立ち...
-
プログラミング
-
パイソンエラーについて
-
パイソンでテキストファイルが...
-
pythonエラー
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
どういうプログラムで組みます...
-
関数の引数に複数のユーザ定義...
-
別のクラスのインスタンスの作り方
-
get() と find() の違いについて
-
パイソンのクラス
-
「arg」は何の略?
-
No route matches [GET] "/post...
-
A1の値をファイル名に指定した...
-
エクセルVBA オートフィルタで...
-
Rubyについて質問です
-
エラー「メソッドまたはデータ...
-
VBAで型が一致しないエラー(バ...
-
教えてください。vb5.0
-
Csvファイルの最終行を取得する...
-
クラス名やモジュール名の競合...
-
HSTLやSSTL等のI/Oピン
-
10円未満を切り捨てる方法は?
-
What class are you in? には何...
-
try ~ catch構文が使えない
-
【BrowseForFolderでデスクトッ...
おすすめ情報