Question

Le problème: J'ai enveloppé certains c ++ code python utilisant SWIG. Du côté python, je veux prendre un pointeur c ++ enveloppé et vers le bas-cast pour être un pointeur sur une sous-classe. J'ai ajouté une nouvelle fonction C ++ au fichier du SWIG qui fait cela vers le bas-casting, mais quand je l'appelle de python, je reçois un TypeError.

Voici les détails:

J'ai deux classes C ++, de base et dérivés. Derived est une sous-classe de base. J'ai une troisième classe, Container, qui contient un Derived, et fournit un accesseur à lui. L'accesseur retourne la Derived comme base const &, comme le montre:

class Container {
  public:
    const Base& GetBase() const {
      return derived_;
    }

  private:
    Derived derived_;
};

J'ai enveloppé ces classes en python utilisant SWIG. Dans mon code python, je voudrais descendre sous pression l'arrière de référence de base vers le bas à un dérivé. Pour ce faire, je l'ai écrit dans le fichier rasade .i une fonction d'assistance en c ++ qui fait le bas-casting:

%inline %{
  Derived* CastToDerived(Base* base) {
    return static_cast<Derived*>(base);
  }
%}

Dans mon code python, j'appeler cette fonction vers le bas-casting:

base = container.GetBase()
derived = CastToDerived(base)

Quand je le fais, je reçois l'erreur suivante:

TypeError: in method 'CastToDerived', argument 1 of type 'Base *'

Pourquoi cela pourrait-il se produire?

Pour référence, voici les bits correspondants du fichier .cxx généré par SWIG; à savoir la fonction d'origine, et son interface ified-python Doppelganger:

  Derived* CastToDerived(Base* base) {
    return static_cast<Derived*>(base);
  }

//  (lots of other generated code omitted)

SWIGINTERN PyObject *_wrap_CastToDerived(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
  PyObject *resultobj = 0;
  Base *arg1 = (Base *) 0 ;
  void *argp1 = 0 ;
  int res1 = 0 ;
  PyObject * obj0 = 0 ;
  Derived *result = 0 ;

  if (!PyArg_ParseTuple(args,(char *)"O:CastToDerived",&obj0)) SWIG_fail;
  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Base, 0 |  0 );
  if (!SWIG_IsOK(res1)) {
    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CastToDerived" "', argument " "1"" of type '" "Base *""'"); 
  }
  arg1 = reinterpret_cast< Base * >(argp1);
  result = (Derived *)CastToDerived(arg1);
  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Derived, 0 |  0 );
  return resultobj;
fail:
  return NULL;
}

Toute aide serait grandement appréciée.

- Matt

Était-ce utile?

La solution

Comme je l'ai fait remarquer ci-dessus, cela semble fonctionner ok avec rasade 1.3.40.

Voici mes fichiers:

c.h:

#include <iostream>
class Base {};
class Derived : public Base
{
    public:
        void f() const { std::cout << "In Derived::f()" << std::endl; }
};
class Container {
  public:
    const Base& GetBase() const {
      return derived_;
    }
  private:
    Derived derived_;
};

C.I.

%module c

%{
#define SWIG_FILE_WITH_INIT
#include "c.h"
%}

%inline %{
  Derived* CastToDerived(Base* base) {
    return static_cast<Derived*>(base);
  }
%}
class Base
{
};

class Derived : public Base
{
    public:
        void f() const;
};

class Container {
  public:
    const Base& GetBase() const;
};

ctest.py

import c

container = c.Container()
b = container.GetBase()
d = c.CastToDerived(b)
d.f()
print "ok"

Une course:

$ swig -c++ -python c.i
$ g++ -fPIC -I/usr/include/python2.6 -c -g c_wrap.cxx
$ g++ -shared -o _c.so c_wrap.o
$ python ctest.py 
In Derived::f()
ok

Autres conseils

2 choses que je remarque dans votre 1er code getBase renvoie une référence à const et seconde qui CastToDerived attend un pointeur vers la base non const.

Même en C ++ vous auriez assez de mal à faire ce travail. Je ne peux pas dire quoi d'autre aurait tort mais je voudrais essayer d'obtenir ce premier fxied.

Est-il possible que vous définissez les temps de classe de base multiples? J'ai eu des problèmes similaires avec ctypes où je involontairement défini de la même classe de structure dans deux modules différents. J'ai aussi eu quelque chose de semblable se passent dans Python pur, où je imp.load_module pour charger une classe de plug-in, créé un objet de cette classe, puis rechargées le module - poof! l'objet créé ne passerait plus un test de isinstance de la classe, puisque la classe rechargées, même si elle avait le même nom, était une autre classe, avec différents id. (Description plus complète cette entrée de blog .)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top