【发布时间】:2011-12-08 13:02:49
【问题描述】:
我在 Ruby C 扩展中看到了类构造函数的奇怪行为。
看一个例子:我们有一个类Foo,它是一个C扩展和一个类Bar,它继承自Foo:
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_new 和 foo_init。
好的,但是如果我们以这种方式更改类 Bar:
# bar.rb
require './foo'
class Bar < Foo
def initialize(param = 1)
end
end
如果我们运行,我们会得到第一个奇怪的东西
x = Bar.new
我们只得到 1 个打印:foo_new。还有foo_init ??
好的,我们可以通过显式调用Foo的构造函数来绕过这个问题:
# bar.rb
require './foo'
class Bar < Foo
def initialize(param = 1)
super()
end
end
如果我们调用 x = Bar.new,我们会得到 2 个打印:foo_new 和 foo_init。
第二个奇怪的东西是这样的: 如果我们打电话
x = Bar.new(2)
我们得到错误
in `new': wrong number of arguments(1 for 0) (ArgumentError)
但是Bar的构造函数接受一个带默认值的参数。
为什么这个?这是 Ruby 错误吗?
(使用 ruby1.9.3-p0 [ x86_64 ] 测试)
【问题讨论】:
-
p Bar.new.class打印出Foo,对吧? -
Bar.new.class打印Bar,Foo.new.class打印Foo
标签: c ruby constructor ruby-c-extension