Как я могу низвергнуть объект c ++ из оболочки Python SWIG? - PullRequest
5 голосов
/ 13 октября 2010

Проблема: я завернул немного кода на С ++ в python, используя SWIG.Что касается Python, я хочу взять завернутый указатель c ++ и уменьшить его до указателя на подкласс.Я добавил новую функцию c ++ в SWI-файл .i, который выполняет преобразование, но когда я вызываю ее из python, я получаю TypeError.

Вот подробности:

У меня есть два класса c ++, Base и Derived.Производный является подклассом Base.У меня есть третий класс, контейнер, который содержит производное и обеспечивает доступ к нему.Метод доступа возвращает Derived в виде константы Base &, как показано:

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

  private:
    Derived derived_;
};

Я обернул эти классы в python, используя SWIG.В моем коде на Python я хотел бы уменьшить базовую ссылку обратно до производного.Чтобы сделать это, я записал в файл swig .i вспомогательную функцию на c ++, которая выполняет преобразование:

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

В своем коде на языке Python я вызываю функцию понижающего преобразования:*

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

При этом я получаю следующую ошибку:

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

Почему это может происходить?

Для справки, здесь приведены соответствующие биты файла .cxx, сгенерированного SWIG;а именно, исходная функция и его двойник с интерфейсом Python:

  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;
}

Любая помощь будет принята с благодарностью.

- Matt

Ответы [ 3 ]

3 голосов
/ 13 октября 2010

Как я прокомментировал выше, похоже, это работает нормально с swig 1.3.40.

Вот мои файлы:

ch:

#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_;
};

ci

%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"

Прогон:

$ 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
0 голосов
/ 13 октября 2010

Возможно ли, что вы определяете базовый класс несколько раз?У меня были похожие проблемы с ctypes, когда я невольно определил один и тот же класс структуры в двух разных модулях.У меня также было нечто подобное в чистом Python, где я использовал imp.load_module для загрузки класса плагина, создал объект этого класса, а затем перезагрузил модуль - poof!созданный объект больше не будет проходить тест isinstance класса, поскольку перезагруженный класс, даже если он имеет то же имя, был другим классом с другим идентификатором.(Более полное описание в этой записи блога .)

0 голосов
/ 13 октября 2010

2 вещи, которые я заметил в вашем коде: 1-ая GetBase возвращает ссылку на const, а вторая, что CastToDerived ожидает указатель на неконстантную Base.

Даже в C ++ у вас будет достаточно проблем с выполнением этой работы. Я не могу сказать, что еще должно быть не так, но я бы сначала попытался это исправить.

...