这是一个代码示例,其中我有一个虚拟类 A,其子类 A_2 和其他以 A 作为参数/返回类型的类/函数。在使用中我可以使用 A_2, A_3 ...
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <iostream>
namespace py = pybind11;
class A {
public:
float i;
A();
virtual void virt_func() = 0;
};
class A_2 : public A {
public:
A_2();
A_2(float value){ i = value ;};
void virt_func() override {std::cout << i << std::endl ;};
};
class B {
public:
B();
A* somefunc(float i){ A* a = new A_2(i); return a;};
};
class C {
public:
C();
void somefunc(A* a){
std::cout << a->i << std::endl ;
};
};
PYBIND11_MODULE(my_module, m)
{
m.doc() = "Some module.";
py::class_<A> py_A(m, "A");
py_A.def(py::init<>());
py::class_<A_2> py_A_2(m, "A_2");
py_A_2.def(py::init<>());
py_A_2.def(py::init<float>(), py::arg("value"));
py_A_2.def("virt_func", &A_2::virt_func);
py::class_<B> py_B(m, "B");
py_B.def(py::init<>());
py_B.def("somefunc", &B::somefunc, py::arg("i"));
py::class_<C> py_C(m, "B");
py_C.def(py::init<>());
py_C.def("somefunc", &C::somefunc, py::arg("a"));
};
以下是对应的编译命令:
g++ \
-O2 \
-std=c++14 \
$(python -m pybind11 --includes) \
example.cpp \
-lMDLSOLVER \
-ldl \
-fPIC \
-c \
-nostartfiles \
-o ./my_module.o
if test -f "my_module.o"
then
g++ -std=c++14 -shared ./my_module.o -o my_module.so
if test -f "my_module.so"
then
rm my_module.o
python test_python.py
fi
fi
以及我们如何从 python 中使用它的 python 示例:
import my_module
b = my_module.B()
a2 = b.somefunc(5.)
c = my_module.C()
c.somefunc(a2)
如果我编译它,我会收到此错误:
erreur: invalid new-expression of abstract class type ‘A’
return new Class{std::forward<Args>(args)...};
^
example.cpp:8:7: note: because the following virtual functions are pure within ‘A’:
class A {
^
example.cpp:13:22: note: virtual void A::virt_func()
virtual void virt_func() = 0;
如果我绑定 A* 而不是 A,则会收到此错误:
Traceback (most recent call last):
File "test_python.py", line 1, in <module>
import my_module
ImportError: /home/catA/tm267619/Workspace/MendelWork/BindingMendel/essai_bin_virtual/my_module.so: undefined symbol: _ZTV1A
使用 A 而不是 A* 作为函数 somefunc 的参数/返回类型并不能以任何方式修复它。
我该怎么做才能正确绑定类 B 和 C?
谢谢
使用 Tranpoline 类解决了问题:
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <iostream>
#include <sstream>
namespace py = pybind11;
class A {
public:
float i = 0;
A() {};
virtual void virt_func() = 0;
void set_i(float val){i = val;};
};
class trampoline_A : public A{
using A::A;
void virt_func() override {
PYBIND11_OVERRIDE_PURE(
void, /* Return type */
A, /* Parent class */
virt_func, /* Name of function in C++ (must match Python name) */
/* Argument(s) */
);
};
};
class A_2 : public A {
public:
A_2() {};
A_2(float value){ i = value ;};
void virt_func() override {std::cout << "calling virt_func from A_2 : " << i << std::endl ;};
};
class B {
public:
B() {};
A* somefunc(float i){ A* a = new A_2(i); return a;};
};
class C {
public:
C() {};
void somefunc(A* a){
std::cout << a->i << std::endl ;
};
};
PYBIND11_MODULE(my_module, m)
{
m.doc() = "Some module.";
py::class_<A, trampoline_A> py_A(m, "A") ;
py_A.def(py::init<>());
py_A.def("set_i", &A::set_i);
py::class_<A_2, A> py_A_2(m, "A_2");
py_A_2.def(py::init<>());
py_A_2.def(py::init<float>());
py_A_2.def("virt_func", &A_2::virt_func);
py_A_2.def("set_i", &A_2::set_i);
py_A_2.def("__repr__", [](A_2& a){
std::stringstream ss;
ss << a.i;
std::string str = ss.str();
std::string result = "A_2 object with value: " + str;
return result;
});
py::class_<B> py_B(m, "B");
py_B.def(py::init<>());
py_B.def("somefunc", &B::somefunc, py::arg("i"));
py::class_<C> py_C(m, "C");
py_C.def(py::init<>());
py_C.def("somefunc", &C::somefunc, py::arg("a"));
};