从C ++调用Ruby类方法

时间:2009-01-30 17:01:43

标签: c++ ruby

我正在尝试从C ++调用类方法。我已经尝试了所有的组合 rb_intern我能想到让它发挥作用,但我什么都没有。

示例类

class CallTest
   def go
    (do something here)
   end
end

尝试使用C ++调用:

rb_funcall(?, rb_intern("go"), 0);

发生了什么?空间?我知道如果我在那里使用Qnil,它会打电话 全局函数,但我更喜欢类方法。

我是朝着错误的方向前进的吗?

另外,如果是,我宁愿不提前知道班级名称 可能,但如果我必须要求我知道它是什么,我可以试试 将它按名称传递给我的申请。

我正在使用SWIG生成绑定。

2 个答案:

答案 0 :(得分:7)

首先,正如您所定义的那样,go不是类方法,而是实例方法

作为面向对象的语言,所有ruby方法都需要一个接收器,即调用该方法的对象。例如方法,接收器是类的实例,对于类方法,接收器本身就是类对象。

?你拥有的占位符是方法调用的接收者的插槽。

如果您想将其保留为实例方法,则需要执行以下操作:

rb_funcall(a_CallTest_instance, rb_intern("go"), 0);

其中a_CallTest_instance是您使用rb_class_new_instance()创建的CallTest实例。

如果你把它变成一个类方法:

class CallTest
  def self.go
    # ...
  end
end

然后你需要使用CallTest类本身作为接收者:

rb_funcall(klass, rb_intern("go"), 0);

您可以使用CallTest

获取对rb_const_get()课程的引用
VALUE klass = rb_const_get(rb_cObject, rb_intern('CallTest'));

在那里使用rb_cObject,因为在全局上下文中定义了CallTest

我建议阅读Pickaxe关于扩展红宝石的章节。

答案 1 :(得分:3)

我也使用SWIG。这些特定的示例文件可以帮助您。

1)test.rb

require 'test.so'
class A
    def func1(buffer)
        puts "ruby instance method: #{buffer}"
    end
end
def func2(buffer)
    puts "ruby global method: #{buffer}"
end
module Z
    def Z.func3(buffer)
        puts "ruby module method: #{buffer}"
    end
end

a = A.new
t = Test::Test1.new()
t.call(a, "func1", "Hello", 5)
t.call(method(:func2), "func2", "Yabaaa", 6)
t.call(Z, "func3", "Yahooooooo", 10)

2)test.h:

#include <ruby.h>
class Test1
{
public:
    void call(VALUE obj, char* func_name, const char* buffer, int size)
    {
        VALUE val = rb_str_new(buffer, size);   
        rb_funcall(obj, rb_intern(func_name), 1, val);
    }
};

3)test.i:

%module test

%{
#include "test.h"
%}

%exception
{
    try
    {
        $action
    }
    catch (std::exception& ex)
    {
        static VALUE cpperror = rb_define_class("test Exception", rb_eStandardError);
        rb_raise(cpperror, ex.what());
    }
    catch (...)
    {
        static VALUE cpperror = rb_define_class("test UnknownException", rb_eStandardError);
        rb_raise(cpperror, "Unknown catched");
    }
}

%include "test.h"

输出:

ruby ./test.rb 
ruby instance method: Hello
ruby global method: Yabaaa
ruby module method: Yahooooooo