2013-12-09 37 views
4

我构建了ruby C++扩展。我有多个C++构造函数。所以我确实创建了几个初始化方法。但它显示一个错误。 谢谢。Ruby C++扩展中的多个构造函数

这是我的代码。

C++头文件

#ifndef CIRCLE_H_ 
    #define CIRCLE_H_ 

class Circle { 
    public: 
     Circle():_radius(0.0) {} 
     Circle(float radius):_radius(radius) {} 
     float getArea() { return 3.14159 * _radius * _radius; } 
     void setRadius(float radius) { _radius=radius; } 
    private: 
     float _radius; 
}; 

#endif /* CIRCLE_H_ */ 

CPP文件

#include<ruby.h> 
    #include"Circle.h" 
    #include<iostream> 

    using namespace std; 

    VALUE classOb; 

    template<class Obtype> void delete_objects(Obtype *ptr){// free pointer 
    delete ptr; 
    } 

    template<class Obtype> VALUE wrap_pointer(VALUE klass,Obtype *ptr){ //wrap c++ object to ruby object 
     return Data_Wrap_Struct(klass,0,delete_objects,ptr); 
    } 

    VALUE alloc_ob(VALUE self){ 
     return wrap_pointer<Circle>(self,new Circle());// add c++ object to ruby  object 
    } 

    VALUE method_initialize(VALUE self,VALUE y){ 
     double x= NUM2DBL(y); 
     Circle *c; 
     Data_Get_Struct(self,Circle,c); 
     c->setRadius(x); 
     return self; 
    } 

    VALUE method_Initialize(VALUE self){ 
     ....... 
     return ; 
    } 
    ............ 

    extern "C" void Init_Test(){ 
    VALUE lemon = rb_define_module("Test"); 
    classOb= rb_define_class_under(lemon,"Circle",rb_cObject); 
    rb_define_alloc_func(classOb,alloc_ob); 
    rb_define_method(classOb, "initialize", (VALUE(*)(ANYARGS))method_initialize,0); 
     rb_define_method(classOb, "initialize", (VALUE(*)(ANYARGS))method_initialize,1); 
    rb_define_method(classOb, "test1", (VALUE(*)(ANYARGS))method_initialize,0); 
    } 

extconf.rb

require 'mkmf' 
    have_library('stdc++'); 
    $CFLAGS << " -Wall" 
    create_makefile('Test'); 

test.rb

require 'rubygems' 
    require '/home/kelum/workspace/Test3/circle/Test' 
    include Test 
    obj=Circle.new 
    obj2=Circle.new(7.1) 

发生错误

Circle.cpp:47:61: error: overloaded function with no contextual type information 
    Circle.cpp:48:61: error: overloaded function with no contextual type information 

问题是什么?

回答

2

你不能有两个initialize方法采用不同的参数,并让Ruby为你选择它们。这是Ruby的限制,并且与C++构造函数的行为不同。从技术上讲,Ruby initialize无论如何都是在构建后发生的--Ruby已经创建了该对象,并且不使用任何参数。

相反,你有两个选择

1)允许initialize采取可变数目则params的,和自己检测不同的可能性。

initialize方法:

VALUE method_initialize(int argc, VALUE* argv, VALUE self) { 
    VALUE y; 

    // You'll want to read up on rb_scan_args 
    rb_scan_args(argc, argv, "01", &y); 

    Circle *c; 
    Data_Get_Struct(self, Circle, c); 

    // Only set radius if y is not nil 
    if (! NIL_P(y)) { 
    c->setRadius(NUM2DBL(y)); 
    } 

    return self; 
} 

如何将其绑定到一个类:

rb_define_method(classOb, "initialize", method_initialize, -1); 

(注意-1,Ruby的信号,该方法采用可变数目的参数)

2)使用不同名称的“工厂”方法,并自己处理构建新对象。

工厂方法:

VALUE method_from_radius(VALUE self, VALUE y) { 
    double x= NUM2DBL(y); 

    volatile VALUE new_circle = alloc_ob(self); 

    Circle *c; 
    Data_Get_Struct(new_circle, Circle, c); 
    c->setRadius(x); 

    return new_circle; 
} 

这种变化也是可能的(也许是最接近于你瞄准):

VALUE method_from_radius(VALUE self, VALUE y) { 
    double x= NUM2DBL(y); 
    return wrap_pointer<Circle>(self,new Circle(x)); 
} 

如何将其绑定到一个类:

rb_define_singleton_method(classOb, "from_radius", method_from_radius, 1); 

注意,单方法有不同的行为,以实例方法,当m在Ruby中调用它们。您可能需要extend Test以及include Test

+0

谢谢尼尔,我会试试这个。 –

+0

没问题。请注意,“工厂”方法可以让你使用不同的C++构造函数,但前提是你通过'wrap_pointer (self,new Circle())'的一些新变体来做到这一点,'' - 我会在上面进行比较。 –

2

的问题是,你尝试绑定两个构造函数:

Circle():_radius(0.0) {} 
    Circle(float radius):_radius(radius) {} 

Ruby没有重载方法,并与它stucks。

尝试删除默认构造函数并将默认值传递给另一个。

希望它有帮助。

+0

谢谢。它只在使用一个构造函数时有效。有没有其他的方式来绑定两个构造函数? –

+0

一般来说,**没有**。但是有一些解决方法,比如[SWIG](http://www.swig.org/Doc1.3/Ruby.html#Ruby_nn20)。我没有自己尝试,但我听说它的工作原理。 – mudasobwa

+0

感谢mudasobwa。 –