2009-02-14 3 views
2

J'utilise SWIG pour encapsuler un script Ruby autour d'une bibliothèque C++. Dans Ruby, je peux hériter d'une classe C++, mais je ne peux pas passer le pointeur résultant à une fonction C++ d'une manière polymorphe.Polymorphisme à travers C++ et Ruby utilisant SWIG

Voici un exemple concret. Le fichier d'interface SWIG définit la classe Animal de base avec son fonction virtuelle():

[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); 

Notez que j'utilise les administrateurs SWIG pour polymorphisme interlangage, mais cela ne semble pas fonctionner. Le script Ruby ressemble à ceci:

[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. 

La dernière ligne dans le script produit cette erreur:

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

donc en quelque sorte SWIG ne me permet pas de traiter l'objet Ruby comme un pointeur à des animaux . Des idées?

Répondre

4

J'ai obtenu une solution à mon problème de Tobias Grimm à la liste de diffusion swig-user. La première partie du problème est le message d'erreur trompeur de SWIG. Le message semble suggérer que je passe le mauvais type de pointeur à ma fonction C++ , mais ce n'est pas le cas. Si vous cochez la classe de l'exception dans Ruby, c'est ObjectPreviouslyDeleted, ce qui signifie que le pointeur struct struct sous-jacente de ma classe Cat est NULL. Donc, le vrai problème est que le pointeur est NULL, pas qu'il a le mauvais type.

Le pointeur est NULL car j'ai simplement oublié d'appeler "super" dans la méthode initialize() de Cat. De cette façon, avec la création de Cat aucune structure C sous-jacente n'est allouée, parce que le constructeur Animal n'est jamais appelé. Oublier d'appeler 'super' est une erreur de Ruby-beginner très commune, surtout pour les gens comme moi qui viennent de C++, qui sont habitués au chaînage automatique des constructeurs.

Donc tout ce que je devais faire était d'ajouter un appel à « super »:

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

Cela fonctionne bien maintenant. Merci, Tobias.

+0

Merci l'homme! Vraiment, si 'super()' n'est pas appelé à partir de la méthode 'initialize()' écrasée, alors l'erreur 'ObjectPreviouslyDeleted' est transmise lors du passage de Ruby à C++. – user1763487

1

Je crois que vous devez définir un helper function qui renvoie un pointeur vers votre instance. J'ai seulement utilisé des pointeurs avec fopen, donc je ne sais pas si ça marchera vraiment, ou s'il y a autre chose qui me manque. Bonne chance!

Questions connexes