I have been trying to cast an abstract class in a C++ program, trying different solution from this webpage and the official documentation, for example this and this , but nothing works. My C++ abstract class is:
class Base
{
public:
virtual ~Base(){};
virtual void foo(){};
};
My wrapper to import to python is:
class BasePy: public Base
{
public:
void foo() override
{
PYBIND11_OVERLOAD_PURE(
void,
Base,
foo);
}
};
My import function and my import:
void import_base(pybind11::module m)
{
using namespace pybind11;
class_<Base, BasePy>(m, "Base")
.def("foo", &Base::foo);
}
PYBIND11_MODULE(baselib, m)
{
import_component(m);
}
I wrote a python class(derived.py):
import baselib
class test(baselib.Base):
def __init__(self):
self.x = 10;
def foo(self):
print(self.x)
And finally my main:
scoped_interpreter guard{};
auto obj = module::import("derived").attr("test")();
// obj = {<pybind11::handle> =
// {<pybind11::detail::object_api<pybind11::handle>> =
// {<pybind11::detail::pyobject_tag> =
// {<No data fields>}, <No data fields>
// },
// m_ptr = 0x7ffff706f1d0
// },
// <No data fields>}
Base* bas = isinstance<Base>(obj) ? (Base*)obj.cast<void*>() : nullptr;
// bas = (Base*) 0x0
"baselib.so" and the executable compiles as "derived.py" works on the pyhton3 interpreter flawlessly. In the interpreter:
derived.test.__base__ : <class 'baselib.base'>
derived.test.__class__ : <class 'pybind11_builtins.pybind11_type'>
derived.baselib == baselib : true
baselib.base.__base__ : <class 'pybind11_builtins.pybind11_object'>
baselib.base.__class__ : <class 'pybind11_builtins.pybind11_type'>
What am I failing to understand?
Eureka, I find a solution: when I import the class I didn't add the init function of the trampoline class:
void import_base(pybind11::module m)
{
using namespace pybind11;
class_<Base,/*Holder*/ BasePy>(m, "Base")
// You can add a holder like std::shared_ptr<Base> in "Holder"
.def(init<>())// <--- THIS
.def("foo", &Base::foo);
}
And in the python class we need to add the "abstract class initializer"(it is the trampoline initializer) like this:
class test(baselib.Base):
def __init__(self):
baselib.Base.__init__(self) // Adding this line
self.x = 10;
And... Voilà. The problem is solved.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.