简体   繁体   English

使用SWIG在C ++和Ruby上实现多态

[英]Polymorphism across C++ and Ruby using SWIG

I use SWIG to wrap a Ruby script around a C++ library. 我使用SWIG将Ruby脚本包装在C ++库中。 In Ruby, I can inherit from a C++ class, but I cannot pass the resulting pointer to a C++ function in a polymorphic way. 在Ruby中,我可以从C ++类继承,但不能以多态方式将结果指针传递给C ++函数。

Here is a concrete example. 这是一个具体的例子。 The SWIG interface file defines base class Animal with virtual function sound(): 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);   

Note that I use SWIG directors for cross-language polymorphism, but this does not seem to work. 请注意,我将SWIG Director用于跨语言多态性,但这似乎不起作用。 The Ruby script looks like this: 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.

The final line in the script produces this error: 脚本中的最后一行会产生此错误:

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

So somehow SWIG does not allow me to treat the Ruby object as a pointer-to-Animal. 因此,SWIG以某种方式不允许我将Ruby对象视为指向动物的指针。 Any ideas? 有任何想法吗?

I got a solution to my problem from Tobias Grimm at the swig-user mailing list. 我从Tobias Grimm的使用者邮件列表中找到了解决问题的方法。 The first part of the problem is SWIG's misleading error message. 问题的第一部分是SWIG的误导性错误消息。 The message seems to suggest that I pass the wrong type of pointer to my C++ function, but this is not the case. 该消息似乎表明我将错误类型的指针传递给了C ++函数,但事实并非如此。 If you check the class of the exception in Ruby, it's ObjectPreviouslyDeleted, meaning that the underlying C struct pointer of my Cat class is NULL. 如果在Ruby中检查异常的类,则为ObjectPreviouslyDeleted,这意味着我的Cat类的基础C结构指针为NULL。 So the real problem is that the pointer is NULL, not that it has the wrong type. 因此,真正的问题是指针为NULL,而不是指针类型错误。

The pointer is NULL because I simply forgot to call "super" in Cat's initialize() method. 指针为NULL,因为我只是忘记了在Cat的initialize()方法中调用“ super”。 This way, with the creation of Cat no underlying C struct gets allocated, because the Animal constructor never gets called. 这样,在创建Cat时,不会分配任何底层C结构,因为从不调用Animal构造函数。 Forgetting to call 'super' is a very common Ruby-beginner's mistake, especially for people like me who come from C++, who are used to automatic constructor chaining. 忘记调用“ super”是Ruby初学者经常犯的错误,特别是对于像我这样从C ++来的人来说,他们习惯于自动构造函数链接。

So all I had to do was add a call to 'super': 因此,我要做的就是添加对“ super”的调用:

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

This now works fine. 现在可以正常工作了。 Thanks, Tobias. 谢谢托比亚斯。

I believe you need to define a helper function that returns a pointer to your instance. 我相信您需要定义一个辅助函数 ,该函数返回一个指向您实例的指针。 I have only used pointers with fopen, so I don't know if this will really work, or if there is something else I am missing. 我仅将指针与fopen一起使用,所以我不知道这是否真的有效,或者是否缺少其他内容。 Good luck! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM