我正在尝试从C ++调用类方法。我已经尝试了所有的组合 rb_intern我能想到让它发挥作用,但我什么都没有。
示例类
class CallTest def go (do something here) end end
尝试使用C ++调用:
rb_funcall(?, rb_intern("go"), 0);
发生了什么?空间?我知道如果我在那里使用Qnil,它会打电话 全局函数,但我更喜欢类方法。
我是朝着错误的方向前进的吗?
另外,如果是,我宁愿不提前知道班级名称 可能,但如果我必须要求我知道它是什么,我可以试试 将它按名称传递给我的申请。
我正在使用SWIG生成绑定。
答案 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