2

我使用 SWIG 将 Ruby 脚本包装在 C++ 库周围。在 Ruby 中,我可以从 C++ 类继承,但不能以多态方式将结果指针传递给 C++ 函数。

这是一个具体的例子。SWIG 接口文件定义了具有虚函数 sound() 的基类 Animal:

[animals.i]
%module(directors="1") animals
%{
#include "animals.h"
%}

// Apply the 'director' feature to a virtual function,
// so that we can override it in Ruby.
%feature("director") Animal::sound;
class Animal {
public:
    Animal();
    virtual ~Animal();
    virtual void sound();
};

class Dog : public Animal {
public:
    Dog();
    virtual ~Dog();
    virtual void sound();
};

// This function takes an Animal* and calls its virtual function sound().
void kick(Animal*, int);   

请注意,我将 SWIG 导向器用于跨语言多态性,但这似乎不起作用。Ruby 脚本如下所示:

[tst.rb]
require 'animals'
include Animals

dog= Dog.new   # Instantiate C++ class
kick(dog, 3)   # Kick the dog 3 times => It barks 3 times.
               # So far so good.

class Cat < Animal   # Inherit from a C++ class
   def initialize
      puts "Creating new cat"
   end

   def sound
      puts "Meow"
   end
end

cat= Cat.new   # Instantiate Ruby class

kick(cat, 9)   # This does not fly.

脚本中的最后一行产生了这个错误:

Expected argument 0 of type Animal *, but got Cat #<Cat:0xb7d621c8>

所以不知何故 SWIG 不允许我将 Ruby 对象视为指向动物的指针。有任何想法吗?

4

2 回答 2

4

我从 swig-user 邮件列表中的 Tobias Grimm 那里得到了我的问题的解决方案。问题的第一部分是 SWIG 的误导性错误消息。该消息似乎表明我将错误类型的指针传递给我的 C++ 函数,但事实并非如此。如果在 Ruby 中检查异常的类,它是 ObjectPreviousDeleted,这意味着我的 Cat 类的底层 C 结构指针为 NULL。所以真正的问题是指针是NULL,而不是它的类型错误。

指针为 NULL,因为我只是忘记在 Cat 的 initialize() 方法中调用“super”。这样,在创建 Cat 时,不会分配底层 C 结构,因为永远不会调用 Animal 构造函数。忘记调用“super”是一个非常常见的 Ruby 初学者错误,尤其是对于像我这样来自 C++ 的人,他们习惯于自动构造函数链接。

所以我所要做的就是添加对“超级”的调用:

class Cat < Animal   # Inherit from a C++ class
   def initialize
      puts "Creating new cat"
      super()
   end
   def sound
      puts "Meow"
   end
end

这现在工作正常。谢谢,托拜厄斯。

于 2009-02-26T15:41:09.650 回答
1

我相信您需要定义一个返回指向您的实例的指针的辅助函数。我只使用了带有 fopen 的指针,所以我不知道这是否真的有效,或者我是否还缺少其他东西。祝你好运!

于 2009-02-17T20:03:12.870 回答