Полиморфизм в C++ и Ruby с использованием SWIG
-
23-08-2019 - |
Вопрос
Я использую SWIG, чтобы обернуть сценарий Ruby вокруг библиотеки C++.В Ruby я могу наследовать класс C++, но не могу передать полученный указатель на функцию C++ полиморфным способом.
Вот конкретный пример.Файл интерфейса SWIG определяет базовый класс Animal с виртуальной функцией sound():
[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.Есть идеи?
Решение
Я получил решение своей проблемы от Тобиаса Гримма в списке рассылки swig-user.Первая часть проблемы — это вводящее в заблуждение сообщение об ошибке SWIG.Похоже, что сообщение предполагает, что я передаю неправильный тип указателя на мою функцию C ++, но это не так.Если вы проверите класс исключения в Ruby, он является объективным удалением, а это означает, что основной указатель C -структуры моего класса CAT является нулевым.Таким образом, реальная проблема заключается в том, что указатель нулевой, а не то, что у него неправильный тип.
Указатель нуль, потому что я просто забыл назвать «супер» в методе инициализации Cat.Таким образом, с созданием кошки, основной C -структуры, распределяется, потому что конструктор животных никогда не вызывается.Забыть называть «Super»-очень распространенная ошибка Ruby-Beginner, особенно для таких людей, как я, которые приезжают из C ++, которые привыкли к автоматическому цепочке конструкторов.
Итак, все, что мне нужно было сделать, это добавить вызов «super»:
class Cat < Animal # Inherit from a C++ class
def initialize
puts "Creating new cat"
super()
end
def sound
puts "Meow"
end
end
Теперь это работает нормально.Спасибо, Тобиас.
Другие советы
Я считаю, что вам нужно определить вспомогательная функция который возвращает указатель на ваш экземпляр.Я использовал только указатели с fopen, поэтому не знаю, действительно ли это будет работать или мне чего-то не хватает.Удачи!