在Python中继承c++的Base,使用SWIG调用抽象方法
Inheriting Base from C++ in Python, call abstract method using SWIG
我有一些麻烦耦合c++(98)与python 3。我在c++中有一些基类,我想在Python中扩展。一些有问题的方法在c++端是纯虚的,因此将在Python端实现。
目前,我可以从c++中调用抽象方法,通过swig,在Python中调用专门化。酷。我在向Python传递参数时遇到了麻烦。
简化问题的最小完整示例:
// iBase.h
#pragma once
#include <memory>
typedef enum EMyEnumeration{
EMyEnumeration_Zero,
EMyEnumeration_One,
EMyEnumeration_Two
}TEMyEnumeration;
class FooBase{
protected:
int a;
public:
virtual int getA() = 0 ;
};
class Foo : public FooBase{
public:
Foo() {a = 2;}
int getA(){return a;}
};
class iBase{
public:
virtual void start() =0;
virtual void run(std::shared_ptr<FooBase> p, TEMyEnumeration enumCode) = 0;
};
右边:
// myif.i
%module(directors="1") DllWrapper
%{
#include <iostream>
#include "iBase.h"
%}
%include <std_shared_ptr.i>
%shared_ptr(FooBase)
%shared_ptr(Foo)
%feature("director") FooBase;
%feature("director") iBase;
%include "iBase.h"
运行swig as:
swig -c++ -python myif.i
swig -Wall -c++ -python -external-runtime runtime.h
myif_wrap编译。cxx -> _DllWrapper。pyd
用下面的代码创建一个*.exe,它将加载_DllWrapper。Pyd库(确保它在同一个目录中!)。同时,将swig生成的DllWrapper.py拷贝到exe目录。//Main_SmartPtr.cpp
#include "stdafx.h"
#include <Python.h>
#include <windows.h>
#include <string>
#include <memory>
#include "iBase.h"
#include "runtime.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string moduleName = "ExampleSmartPtr";
// load *.pyd (actually a dll file which implements PyInit__<swigWrapperName>)
auto handle =LoadLibrary("_DllWrapper.pyd");
// getting an instance handle..
Py_Initialize();
PyObject *main = PyImport_AddModule("__main__");
PyObject *dict = PyModule_GetDict(main);
PyObject *module = PyImport_Import(PyString_FromString(moduleName.c_str()));
PyModule_AddObject(main, moduleName.c_str(), module);
PyObject *instance = PyRun_String(string(moduleName+string(".")+moduleName+string("()")).c_str(), Py_eval_input, dict, dict);
//calling start() in the Python derived class..
//PyObject *result = PyObject_CallMethod(instance, "start", (char *)"()");
// trying to call run in the Python derived class..
shared_ptr<Foo> foo = make_shared<Foo>();
EMyEnumeration enumCode = EMyEnumeration_Two;
string typeName1 = "std::shared_ptr <FooBase> *";
swig_type_info* info1 = SWIG_TypeQuery(typeName1.c_str());
auto swigData1 = SWIG_NewPointerObj((void*)(&foo), info1, SWIG_POINTER_OWN);
string typeName2 = "TEMyEnumeration *";
swig_type_info* info2 = SWIG_TypeQuery(typeName2.c_str());
auto swigData2 = SWIG_NewPointerObj((void*)(&enumCode), info2, SWIG_POINTER_OWN);
auto result = PyObject_CallMethod(instance, "run", (char *)"(O)(O)", swigData1, swigData2);
return 0;
}
创建一个新的Python文件,并把它放在exe的目录下:
#ExampleSmartPtr.py
import DllWrapper
class ExampleSmartPtr(DllWrapper.iBase):
def __init__(self): # constructor
print("__init__!!")
DllWrapper.iBase.__init__(self)
def start(self):
print("start")
return 0
def run(self, data, enumCode):
print("run")
print("-> data: "+str(data))
print("-> enumCode: "+str(enumCode))
print (data.getA())
return 1
运行exe的输出为:
__init__!!
run
-> data: (<DllWrapper.FooBase; proxy of <Swig Object of type 'std::shared_ptr< FooBase > *' at 0x00000000014F8B70> >,)
-> enumCode: (<Swig Object of type 'TEMyEnumeration *' at 0x00000000014F89F0>,)
如何"解引用"enumCode到一个简单的int?如何在python类run()中调用print (data.getA()) ?在当前的形式下,它不打印任何东西。
这不是一个真正的答案,但我从2005年开始阅读讨论,这是有道理的,它不应该是可能的。如果你在Python端,执行以下操作,你的枚举将被"解引用"为一个简单的整数。
import ExampleSmartPtr
instance = ExampleSmartPtr.ExampleSmartPtr()
swigData1 = ExampleSmartPtr.DllWrapper.Foo()
swigData2 = ExampleSmartPtr.DllWrapper.EMyEnumeration_Two
instance.run(swigData1,swigData2)
打印
__init__!!
run
-> data: <DllWrapper.Foo; proxy of <Swig Object of type 'std::shared_ptr< Foo > *' at 0x7f8825c0b7e0> >
-> enumCode: 2
我认为问题是两个不同的变量在起作用。原始的c++虚函数表和Swig Object
的虚函数表。只是好奇,在什么情况下,从c++中使用c++类的Python后代是有意义的?
似乎有人在做同样的事情!
我所做的是编译*。pyd with -DSWIG_TYPE_TABLE=iBase.
然后我把这个添加到cpp端的主应用程序中:
iBase *python2interface(PyObject *obj) {
void *argp1 = 0;
swig_type_info * pTypeInfo = SWIG_TypeQuery("iBase *");
const int res = SWIG_ConvertPtr(obj, &argp1,pTypeInfo, 0);
if (!SWIG_IsOK(res)) {
abort();
}
return reinterpret_cast<iBase*>(argp1);
}
并像这样调用python的实现:
auto foo = make_shared<Foo>();
TEMyEnumeration enumCode = EMyEnumeration_Two;
python2interface(instance)->run(foo, enumCode);
最后,我用-DSWIG_TYPE_TABLE=iBase再次编译了c++实现。
工作像一个魅力!
相关文章:
- 无法使用 SWIG 在 Python 中实例化C++类(获取属性错误)
- 使用 SWIG 更改生成的 CS 函数中的返回类型
- 使用 swig 追加到字节数组
- 如何使用 swig 修改类构造函数以保留对其中一个构造函数参数的引用?
- <string> 如何在使用 SWIG 时将 int 数组和 List 作为参数传递给 C# C++
- 使用SWIG从C++回调到C#
- 如何使用 swig C++命名空间作为 python 模块公开
- 使用 Swig 在成员中包装具有互斥锁的 C++ 类时出现问题
- 如何使用 SWIG 接口访问 python 中的 C++ typedef'd 结构
- 使用SWIG将numpy数组元素(int)传递给c++int
- 错误:使用 SWIG 的未知类型名称"类"
- C++ 使用 SWIG 和 Visual Studio 2017 在 python 中导入 DLL
- C++类在Python中使用SWIG的奇怪行为
- 使用 SWIG 绑定 Python/C++ 模板
- 使用 c++ uint8_t * 从 c# 使用 SWIG
- 使用 SWIG 初始化对 C# 共享指针的引用,从C++
- 包装C++函数以使用 SWIG 获取 Lua 字符串表
- 如何使用 SWIG 将 C++ int** 返回值给 Python
- 使用 swig 在 Python 中分段错误(核心转储),但当我更改变量名称时它可以工作
- 使用 SWIG 将C++类包装在 Python 中