2011-12-08 64 views
2

在Ruby C擴展中,我看到了class costructor的奇怪行爲。
參見一個例子:我們有一個類Foo是一個C擴展和類BarFoo繼承:Ruby C擴展中的構造函數的奇怪行爲

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 

好吧,讓我們看到奇怪的東西...
在這種情況下都去確定:

x = Bar.new 

我們得到了2個打印:foo_newfoo_init
好啊好啊,但如果我們改變這樣的類Bar

# bar.rb 
require './foo' 

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

我們有第一怪的東西,如果我們運行

x = Bar.new 

我們只能得到1打印:foo_new。和foo_init ??如果我們調用x = Bar.newfoo_newfoo_init
好了,我們可以繞過這個問題將顯式調用的Foo構造:

# bar.rb 
require './foo' 

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

我們拿到的2幅版畫。

第二怪的東西是這樣的: 如果我們調用

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

好的,謝謝!我遵循這個文檔:http:// ruby​​-doc。org/docs/ProgrammingRuby/html/ext_ruby.html(請參閱示例)... – Pioz