2011-12-08 18 views
2

Ruby Cエクステンションのクラスcostructorで奇妙な動作が見られました。
は、例を参照してください:我々は、Cの拡張とFooから継承するクラスBarあるクラスFooを持っている:Ruby Cエクステンションのcostructorでの不思議な動作

extconf.rbは

# extconf.rb 
require 'mkmf' 
create_makefile('foo/foo') 

foo.cの

// foo.c 
#include "ruby.h" 
#include <stdio.h> 

VALUE 
foo_new (VALUE class) 
{ 
    printf ("foo_new\n"); 
    int *ptr; 
    VALUE tdata = Data_Wrap_Struct (class, 0, 0, ptr); 
    rb_obj_call_init (tdata, 0, 0); 
    return tdata; 
} 

VALUE 
foo_init (VALUE self) 
{ 
    printf ("foo_init\n"); 
    return self; 
} 

VALUE 
foo_plus_one (VALUE self, VALUE x) 
{ 
    printf ("foo_plus_one\n"); 
    return INT2FIX (FIX2INT (x) + 1); 
} 

void 
Init_foo() 
{ 
    VALUE foo = rb_define_class ("Foo", rb_cObject); 
    rb_define_singleton_method (foo, "new", foo_new, 0); 
    rb_define_method (foo, "initialize", foo_init, 0); 
    rb_define_method (foo, "plus_one", foo_plus_one, 1); 
} 

bar.rb

# bar.rb 
require './foo' 

class Bar < Foo 
end 

もOKですが、奇妙な原料を見てみましょう...この状況で
すべてがOKに行く:foo_newfoo_init

x = Bar.new 

我々は2枚のプリントを取得します。
[OK]を良い、しかし、我々はこのようにクラスBarを変更した場合:foo_new

# bar.rb 
require './foo' 

class Bar < Foo 
    def initialize(param = 1) 
    end 
end 

は、我々が最初に奇妙なものを持っている私たちは

x = Bar.new 

を実行した場合、我々は1つだけのプリントを得ます。そしてfoo_init ??
[OK]を、私たちはFooのコンストラクタに明示的な呼び出しを追加し、この問題を回避することができます

# bar.rb 
require './foo' 

class Bar < Foo 
    def initialize(param = 1) 
    super() 
    end 
end 

我々は2枚の印刷物を得る:我々はx = Bar.newを呼び出す場合foo_newfoo_initを。我々は

x = Bar.new(2) 

を呼び出す場合、我々は、デフォルト値を持つ一つのパラメータを受け入れるエラー

in `new': wrong number of arguments(1 for 0) (ArgumentError) 

しかしBarのコンストラクタを取得 :

二奇妙なものがこれです。
これはなぜですか?これはRubyのバグですか?

(ruby1.9.3-P0 [x86_64版]でテスト済み)

+0

'p個のBar.new.class'プリント' Foo'を、右? –

+0

'Bar.new.class'は' Bar'を出力し、 'Foo.new.class'は' Foo'を出力します – Pioz

答えて

3

あなたは引数を取りませんし::newを定義し、そのwrong number of arguments(1 for 0)が期待されています。とにかく、::newは再定義しないでください。正しい方法は、::allocateメソッドを定義することです(::newは内部的に呼び出します)。

これは動作するはずです:

// foo.c 
#include "ruby.h" 
#include <stdio.h> 

void foo_free (void *ptr) { 
    free (ptr); 
} 

VALUE foo_alloc (VALUE class) { 
    printf ("foo_alloc\n"); 
    int *ptr = malloc(sizeof(int)); 
    return Data_Wrap_Struct (class, 0, foo_free, ptr); 
} 

VALUE foo_init (VALUE self) { 
    printf ("foo_init\n"); 
    return self; 
} 

void Init_foo (void) { 
    VALUE cFoo = rb_define_class ("Foo", rb_cObject); 
    rb_define_alloc_func (cFoo, foo_alloc); 
    rb_define_method (cFoo, "initialize", foo_init, 0); 
} 
+0

Ok、ありがとう!!!私はこの文書に従っています:http:// ruby​​-doc。org/docs/ProgrammingRuby/html/ext_ruby.html(例を参照)... – Pioz

関連する問題