2013-12-09 2 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 сигнал Руби, что метод принимает переменное число аргументов)

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); 

Обратите внимание, что методы singleton имеют различное поведение для методов экземпляра, когда m анимируя их в Ruby. Возможно, вам понадобится extend Test, а также include Test.

+0

спасибо Нейлу, я попробую это. –

+0

Нет проблем. Обратите внимание, что метод «заводской» метод позволит использовать ваши различные конструкторы C++, но только если вы сделаете это с помощью некоторых новых вариантов 'wrap_pointer (self, new Circle());' - я покажу это выше для сравнения. –

2

Проблема заключается в том, что вы пытаетесь связать два конструктора:

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

Рубин не имеет перегруженных методов и это заклинивание с ним.

Попробуйте удалить конструктор по умолчанию и передать значение по умолчанию другому.

Надеюсь, это поможет.

+0

спасибо. он работает, когда используется только один конструктор. есть ли другой способ связать два конструктора? –

+0

Вообще говоря, ** нет **. Но есть некоторые обходные пути, такие как [SWIG] (http://www.swig.org/Doc1.3/Ruby.html#Ruby_nn20). Я сам не пробовал, но я слышал, что это работает. – mudasobwa

+0

спасибо mudasobwa. –

Смежные вопросы