2

我一直在浏览有关如何将 Ruby 嵌入到 C++ 程序中的教程。我发现了如何通过“rb_define_class”和“rb_define_class_under”定义一个类以及通过“rb_define_method”定义方法。现在我需要一个很好的例子来解释如何用一个用 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;
    }

我还需要一种处理垃圾收集的方法,以释放我的包装对象(并做其他事情)。抱歉英语不好,感谢愿意回答这个问题的人!

4

1 回答 1

3

要与 Ruby 的内存管理集成,您需要实现两个函数,为您的一个对象分配和释放内存 - 两者都不能带参数。Ruby 会将您的 C++ 数据结构“附加”到 Ruby selfVALUE 上,您需要使用几种方法来创建该附件,并从self.

到目前为止,您的代码已经足够接近,我刚刚在这里为您填补了空白:

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;
}
于 2013-12-20T11:50:37.727 回答