Ruby C++扩展中的多个构造函数

Multiple constructors in Ruby C++ extension

本文关键字:构造函数 C++ 扩展 Ruby      更新时间:2023-10-16

我构建了ruby C++扩展。我在C++中有多个构造函数。所以我创建了几个initialize方法。但它显示了一个错误。非常感谢。

这是我的密码。

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

问题出在哪里?

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

相反,你有两个选项

1)允许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 );

请注意,在Ruby中操作singleton方法时,其行为与实例方法不同。您可能需要extend Testinclude Test

问题是您试图绑定两个构造函数:

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

Ruby没有重载的方法,而且它很难处理。

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

希望能有所帮助。