Как уволить объект C ++ из обертки Python Swig?
Вопрос
Проблема: я завернул немного кода C ++ в Python, используя SWIG. На стороне Python я хочу взять обернутый указатель C ++ и понизить его, чтобы быть указателем на подкласс. Я добавил новую функцию C ++ в файл Swig .i, который делает это понижающимся, но когда я называю ее из Python, я получаю тип Enror.
Вот подробности:
У меня есть два класса C ++, база и получены. Получен является подкласс базы. У меня есть третий класс, контейнер, который содержит производный, и предоставляет ему аксессуар. Доход возвращает полученную как базу Const &, как показано:
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; а именно исходная функция, и ее питон-интерфейс-двойник:
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;
}
Любая помощь будет очень оценена.
- Мэтт
Решение
Как я прокомментировал выше, это, кажется, работает нормально со 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
Другие советы
2 вещи, которые я замечаю в вашем коде.
Даже в C ++ у вас будет достаточно проблем с созданием этой работы. Я не могу сказать, что еще должно быть не так, но я бы попытался сначала получить этот фсим.
Возможно ли, что вы определяете базовый класс несколько раз? У меня были похожие проблемы с ctypes, где я невольно определил один и тот же класс структуры в двух разных модулях. У меня также было что -то подобное в Pure Python, где я использовал imp.load_module для загрузки класса плагина, создал объект этого класса, а затем перезагружал модуль - poof! Созданный объект больше не будет проходить тест на Isinstance на класс, поскольку перезагруженный класс, хотя он имел одинаковое имя, был другим классом, с другим идентификатором. (Более полное описание в Эта запись в блоге.)