1

我在下面包含了一个最小的工作示例 - 它可以使用典型的 pybind11 指令进行编译(我使用 cmake)。

我有一个抽象基类Abstract,它是纯虚拟的。我可以使用“蹦床类”轻松地将其包装在 pybind11 中(pybind11 对此进行了详细记录)。

此外,我有一个 , 的具体实现AbstractToBeWrapped它也使用 pybind11 包装。

我的问题是我有一些客户端代码接受任意PyObject*(或者,在本例中为 pybind11 的 wrapper py::object)并希望将其转换为Abstract*.

但是,如我的示例所示,我无法py::objectAbstract*.

我没有问题将其转换为Python 解释器正在发送的 Abstract*` ToBeWrapped*,然后将其存储为抽象基类的目的。Abstract*', however this would require my client code to know ahead of time what kind of

TL;博士

是否可以修改此代码,以便客户端accessMethod能够任意处理Abstract*从 python 解释器传递的内容?

#include <pybind11/pybind11.h>
#include <iostream>

namespace py = pybind11;

// abstract base class - cannot be instantiated on its own
class Abstract
{
    public:
        virtual ~Abstract() = 0;
        virtual std::string print() const = 0;
};

Abstract::~Abstract(){}

// concrete implementation of Abstract
class ToBeWrapped : public Abstract
{
    public:
        ToBeWrapped(const std::string& msg = "heh?")
            : myMessage(msg){};
        std::string print() const override
        {
            return myMessage;
        }

    private:
        const std::string myMessage;
};

// We need a trampoline class in order to wrap this with pybind11
class AbstractPy : public Abstract
{
    public:
        using Abstract::Abstract;

        std::string print() const override
        {
            PYBIND11_OVERLOAD_PURE(
                std::string, // return type
                Abstract, // parent class
                print, // name of the function
                // arguments (if any)
            );
        }
};

// I have client code that accepts a raw PyObject* - this client code base implements its
// own python interpreter, and calls this "accessMethod" expecting to convert the python
// object to its c++ type.
//
// Rather than mocking up the raw PyObject* method (which would be trivial) I elected to
// keep this minimal example 100% pybind11
void accessMethod(py::object obj)
{
    // runtime error: py::cast_error
    //Abstract* casted = obj.cast<Abstract*>();

    // this works
    Abstract* casted = obj.cast<ToBeWrapped*>();
}

PYBIND11_MODULE(PyMod, m)
{
    m.doc() = R"pbdoc(
    This is a python module
    )pbdoc";

    py::class_<Abstract, AbstractPy>(m, "Abstract")
        .def("print", &Abstract::print)
    ;

    py::class_<ToBeWrapped>(m, "WrappedClass")
        .def(py::init<const std::string&>())
    ;
    m.def("access", &accessMethod, "This method will attempt to access the wrapped type");
}
4

1 回答 1

2

您需要声明层次关系,因此:

py::class_<ToBeWrapped>(m, "WrappedClass")

应该:

py::class_<ToBeWrapped, Abstract>(m, "WrappedClass")
于 2019-11-08T19:33:48.537 回答