2013-12-20 40 views
2

我一直在浏览关于如何将Ruby嵌入到C++程序中的教程。我已经发现如何通过“rb_define_class”和“rb_define_class_under”以及通过“rb_define_method”定义一个类。现在我需要一个很好的例子来解释如何用C++编写的ruby类来包装现有的C++对象(指针)。例如:在Ruby和C++之间交换数据

class MyClass 
    { 
    public: 
     MyClass(); 
     void MyMethod(); 
    }; 

    VALUE myclass_init(VALUE self) 
    { 
     // I'd like to create a new MyClass instance and store its pointer inside "self" 
    } 

    VALUE myclass_meth(VALUE self) 
    { 
     // Now i need to retrieve the pointer to the object and call its method 
    } 

    int main(int argc, char* argv[]) 
    { 
     ruby_init(); 
     ruby_init_loadpath(); 

     VALUE myclass = rb_define_class("MyWrapperClass", rb_cObject); 
     rb_define_method(myclass, "initialize", (VALUE(*)(...))myclass_init, 0); 
     rb_define_method(myclass, "myWrappedMethod", (VALUE(*)(...))myclass_meth, 0); 

     // Loading ruby script skipped.. 

     ruby_finalize(); 

     return 0; 
    } 

我还需要一种方法来处理垃圾收集,以释放我包装的对象(和其他东西)。对不起,英文不好,谢谢谁会试图回答这个问题!

+0

你见过:http://media.pragprog.com/titles/ruby3/ext_ruby.pdf ?您可能想看看我的示例gem:https://github.com/neilslater/ruby_nex_cpp(这是C++的本地扩展,不是嵌入式Ruby,但大部分API集成都是相同的)。另外看看RICE,它有更完整的图书馆。 –

+0

谢谢!这正是我一直在寻找的! – napco

+0

另请参阅我的答案 - 我将它放到代码的上下文中。 –

回答

3

要与Ruby的内存管理集成,需要实现两个为对象之一分配和释放内存的函数 - 两者都不需要参数。 Ruby将把你的C++数据结构“附加”到Ruby self VALUE中,并且你需要使用一些方法来创建该附件,并从self获取C++。

你到目前为止的代码是足够接近,我刚才填充在间隙为你在这里:

class MyClass 
{ 
public: 
    MyClass(); 
    void MyMethod(); 
}; 

////////////////////////////////////////////////////////// 
// The next five are the functions that you were missing 
// (although you could factor this differently if you chose) 

MyClass *rb_create_myclass_obj() { 
    return new MyClass(); 
} 

void rb_delete_myclass_obj(MyClass *p_myclass) { 
    delete p_myclass; 
    return; 
} 

VALUE myclass_as_ruby_class(MyClass *p_myclass , VALUE klass) { 
    return Data_Wrap_Struct(klass, 0, rb_delete_myclass_obj, p_myclass); 
} 

VALUE myclass_alloc(VALUE klass) { 
    return myclass_as_ruby_class(rb_create_myclass_obj(), klass); 
} 

MyClass *get_myclass_obj(VALUE obj) { 
    MyClass *p_myclass; 
    Data_Get_Struct(obj, MyClass, p_myclass); 
    return p_myclass; 
} 

////////////////////////////////////////////////////////// 

VALUE myclass_init(VALUE self) 
{ 
    // You need do nothing here, Ruby will call myclass_alloc for 
    // you. 
    return self; 
} 

VALUE myclass_meth(VALUE self) 
{ 
    MyClass *p_myclass = get_myclass_obj(self); 
    p_myclass->MyMethod(); 

    // If MyMethod returns some C++ structure, you will need to convert it 
    // Here's how to return Ruby's nil 

    return Qnil; 
} 

int main(int argc, char* argv[]) 
{ 
    ruby_init(); 
    ruby_init_loadpath(); 

    VALUE myclass = rb_define_class("MyWrapperClass", rb_cObject); 

    // The alloc function is how Ruby hooks up the memory management 
    rb_define_alloc_func(myclass, myclass_alloc); 

    rb_define_method(myclass, "initialize", (VALUE(*)(...))myclass_init, 0); 
    rb_define_method(myclass, "myWrappedMethod", (VALUE(*)(...))myclass_meth, 0); 

    // Loading ruby script skipped.. 

    ruby_finalize(); 

    return 0; 
}