Il polimorfismo attraverso C ++ e Ruby utilizzando SWIG
-
23-08-2019 - |
Domanda
Io uso SWIG per avvolgere uno script di Ruby intorno una libreria C ++. In rubino, posso ereditare da una classe C ++, ma non posso passare il puntatore risultante a una funzione C ++ in modo polimorfo.
Ecco un esempio concreto. Il file di interfaccia SWIG definisce Animal classe di base con il suono funzione virtuale ():
[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);
Si noti che uso direttori SWIG per il polimorfismo cross-language, ma questo non sembra funzionare. Lo script di Ruby si presenta così:
[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.
L'ultima riga nello script genera questo errore:
Expected argument 0 of type Animal *, but got Cat #<Cat:0xb7d621c8>
Così in qualche modo SWIG non mi permette di trattare l'oggetto di Ruby come un animale puntatore a. Tutte le idee?
Soluzione
Ho una soluzione al mio problema da Tobias Grimm alla mailing list sorso-user. La prima parte del problema è messaggio di errore fuorviante di SWIG. Il messaggio sembra suggerire che passo il tipo sbagliato di puntatore alla mia C ++ funzione, ma questo non è il caso. Se si seleziona la classe di eccezione in rubino, è ObjectPreviouslyDeleted, il che significa che il puntatore C struct sottostante della mia classe Cat è nullo. Quindi il vero problema è che il puntatore è NULL, non che ha il tipo sbagliato.
Il puntatore è NULL perché ho semplicemente dimenticato di chiamare "super" in inizializzazione del gatto () metodo. In questo modo, con la creazione di Cat C sottostante struct viene allocato, poiché il costruttore degli animali non viene mai chiamato. Dimenticando di chiamare 'super' è errore molto comune Ruby-principianti, in particolare per le persone come me che vengono da C ++, che sono abituati a catena automatica costruttore.
Quindi, tutto quello che dovevo fare era aggiungere una chiamata al 'super':
class Cat < Animal # Inherit from a C++ class
def initialize
puts "Creating new cat"
super()
end
def sound
puts "Meow"
end
end
Questa ora funziona benissimo. Grazie, Tobias.