这个答案有两个部分。首先,您需要以允许 Python 实现随意覆盖其中一部分的方式在 Python 中公开您的接口。然后你需要展示你的 C++ 程序(在main 如何调用 Python。
将现有接口暴露给 Python:
使用 SWIG 很容易完成第一部分。我稍微修改了您的示例场景以解决一些问题并添加了一个额外的测试功能:
// myif.h
class myif {
public:
virtual float myfunc(float a) = 0;
};
inline void runCode(myif *inst) {
std::cout << inst->myfunc(5) << std::endl;
}
现在我将在不将 Python 嵌入您的应用程序的情况下查看问题,即您在 Python 中启动异常,而不是在 C++ 中的 int main() 中启动。不过,稍后添加它相当简单。
首先获取cross-language polymorphism working:
%module(directors="1") module
// We need to include myif.h in the SWIG generated C++ file
%{
#include <iostream>
#include "myif.h"
%}
// Enable cross-language polymorphism in the SWIG wrapper.
// It's pretty slow so not enable by default
%feature("director") myif;
// Tell swig to wrap everything in myif.h
%include "myif.h"
为此,我们在全球范围内启用了 SWIG 的导演功能,专门针对我们的界面。不过,其余部分都是相当标准的 SWIG。
我写了一个测试 Python 实现:
import module
class MyCl(module.myif):
def __init__(self):
module.myif.__init__(self)
def myfunc(self,a):
return a*2.0
cl = MyCl()
print cl.myfunc(100.0)
module.runCode(cl)
这样我就可以编译并运行它了:
痛饮 -python -c++ -Wall myif.i
g++ -Wall -Wextra -shared -o _module.so myif_wrap.cxx -I/usr/include/python2.7 -lpython2.7
python mycl.py
200.0
10
正是您希望从该测试中看到的。
在应用程序中嵌入 Python:
接下来我们需要实现您的 mymain.cc 的真实版本。我已经把它可能看起来的草图放在一起:
#include <iostream>
#include "myif.h"
#include <Python.h>
int main()
{
Py_Initialize();
const double input = 5.0;
PyObject *main = PyImport_AddModule("__main__");
PyObject *dict = PyModule_GetDict(main);
PySys_SetPath(".");
PyObject *module = PyImport_Import(PyString_FromString("mycl"));
PyModule_AddObject(main, "mycl", module);
PyObject *instance = PyRun_String("mycl.MyCl()", Py_eval_input, dict, dict);
PyObject *result = PyObject_CallMethod(instance, "myfunc", (char *)"(O)" ,PyFloat_FromDouble(input));
PyObject *error = PyErr_Occurred();
if (error) {
std::cerr << "Error occured in PyRun_String" << std::endl;
PyErr_Print();
}
double ret = PyFloat_AsDouble(result);
std::cout << ret << std::endl;
Py_Finalize();
return 0;
}
它基本上只是标准的embedding Python in another application。它有效,并且提供了您希望看到的内容:
g++ -Wall -Wextra -I/usr/include/python2.7 main.cc -o main -lpython2.7
。/主要的
200.0
10
10
难题的最后一块是能够将您在 Python 中创建实例时获得的 PyObject* 转换为 myif *。 SWIG 再次使这变得相当简单。
首先,我们需要让 SWIG 为我们在头文件中公开其运行时。我们通过额外调用 SWIG 来做到这一点:
痛饮 -Wall -c++ -python -external-runtime runtime.h
接下来,我们需要重新编译我们的 SWIG 模块,显式地提供 SWIG 知道的名称类型表,以便我们可以从 main.cc 中查找它。我们重新编译 .so 使用:
g++ -DSWIG_TYPE_TABLE=myif -Wall -Wextra -shared -o _module.so myif_wrap.cxx -I/usr/include/python2.7 -lpython2.7
然后我们在 main.cc 中添加一个辅助函数,用于将 PyObject* 转换为 myif*:
#include "runtime.h"
// runtime.h was generated by SWIG for us with the second call we made
myif *python2interface(PyObject *obj) {
void *argp1 = 0;
swig_type_info * pTypeInfo = SWIG_TypeQuery("myif *");
const int res = SWIG_ConvertPtr(obj, &argp1,pTypeInfo, 0);
if (!SWIG_IsOK(res)) {
abort();
}
return reinterpret_cast<myif*>(argp1);
}
现在我们可以在main()中使用它:
int main()
{
Py_Initialize();
const double input = 5.5;
PySys_SetPath(".");
PyObject *module = PyImport_ImportModule("mycl");
PyObject *cls = PyObject_GetAttrString(module, "MyCl");
PyObject *instance = PyObject_CallFunctionObjArgs(cls, NULL);
myif *inst = python2interface(instance);
std::cout << inst->myfunc(input) << std::endl;
Py_XDECREF(instance);
Py_XDECREF(cls);
Py_Finalize();
return 0;
}
最后我们必须用-DSWIG_TYPE_TABLE=myif 编译 main.cc,这给出:
。/主要的
11