Полиморфизм в C ++ и Ruby с использованием SWIG - PullRequest
2 голосов
/ 14 февраля 2009

Я использую SWIG, чтобы обернуть скрипт Ruby вокруг библиотеки C ++. В Ruby я могу наследовать от класса C ++, но не могу передать полученный указатель на функцию C ++ полиморфным способом.

Вот конкретный пример. Файл интерфейса SWIG определяет базовый класс 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 как указатель на Animal. Есть идеи?

Ответы [ 2 ]

4 голосов
/ 26 февраля 2009

Я получил решение моей проблемы от Тобиаса Гримма в списке рассылки swig-user. Первая часть проблемы - вводящее в заблуждение сообщение об ошибке SWIG. Похоже, что сообщение подсказывает, что я передаю неверный тип указателя на мой C ++ функция, но это не так. Если вы проверите класс исключения в Ruby это ObjectPreviouslyDeleted, что означает, что базовый указатель структуры C моего класса Cat имеет значение NULL. Итак, настоящая проблема в том, что указатель равен NULL, не то, что он имеет неправильный тип.

Указатель НЕДЕЙСТВИТЕЛЕН, потому что я просто забыл назвать "супер" в методе инициализации Cat () метод. Таким образом, при создании Cat не выделяется ни одна базовая структура C, потому что конструктор Animal никогда не вызывается. Забыть звание «супер» - очень распространенная ошибка начинающего Руби, особенно для таких как я, которые пришли из C ++ и привыкли к автоматическому построению цепочек.

Так что все, что мне нужно было сделать, это добавить вызов 'super':

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

Теперь это работает нормально. Спасибо, Тобиас.

1 голос
/ 17 февраля 2009

Я считаю, что вам нужно определить вспомогательную функцию , которая возвращает указатель на ваш экземпляр. Я использовал указатели только с fopen, так что я не знаю, будет ли это действительно работать, или я что-то упустил. Удачи!

...