我构建了ruby C ++扩展。我在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
问题是什么?
答案 0 :(得分:2)
问题是你试图绑定两个构造函数:
Circle():_radius(0.0) {}
Circle(float radius):_radius(radius) {}
Ruby没有重载方法,它坚持使用它。
尝试删除默认构造函数并将默认值传递给另一个。
希望它有所帮助。
答案 1 :(得分:2)
你不能有两个initialize
方法采用不同的参数,并让Ruby为它们选择它们。这是Ruby的限制,与C ++构造函数的行为不同。从技术上讲,Ruby initialize
无论如何都会在构造之后发生 - Ruby已经创建了这个对象,而且没有使用任何参数。
相反,你有两个选择
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中操作单例方法时,单例方法与实例方法的行为不同。您可能需要extend Test
以及include Test
。