2013-12-09 20 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。 –