Этот ответ состоит из двух частей.Во-первых, вам нужно представить свой интерфейс в 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, а не в int main()
в C ++. Впрочем, добавить это позже довольно просто.
Сначала получим межфилиальный полиморфизм, работающий :
%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)
Сзатем я смог скомпилировать и запустить это:
swig -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;
}
Это просто стандартный встраивание Python в другое приложение .Он работает и дает именно то, что вы хотели бы увидеть также:
g++ -Wall -Wextra -I/usr/include/python2.7 main.cc -o main -lpython2.7
./main
200.0
10
10
Последний кусок головоломки - это возможность преобразовать PyObject*
, который вы получите от создания экземпляра в Pythonв myif *
.SWIG снова делает это достаточно простым.
Сначала нам нужно попросить 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
Затем мы добавляем вспомогательную функцию для преобразования PyObject*
в myif*
в нашем main.cc:
#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;
}
Наконец мы должны скомпилировать main.cc с -DSWIG_TYPE_TABLE=myif
, и это даст:
./main
11