首页 > 解决方案 > 带有 pybind 的多态类

问题描述

我想使用 pybind 将多态 c++ 类层次结构包装到 python 中。

我的意图是 python 类继承自 python 代码中包装的 c++ 类并覆盖一些函数。在我下面的示例中,有一个继承自 C++ 类 Animal 和覆盖函数 go() 的 python 类 Cat。这是有效的, print(test.call_go(c)打印“喵!喵!喵!” 正如预期的那样。

Python 类 Bello 继承自 c++ 类 Dog,应该覆盖函数 bark() 和 go()。但它不起作用。bark() 和 go() 是否被 Bello 类覆盖。

print(test.call_go(b))打印“汪!汪!汪!”。我期待“grrrrr!grrrrr!grrrrr!”

print(test.call_bark(b)) 打印“哇!”。我期待“grrrrr!”

似乎 pybind 继承仅适用于多态性的一个级别。我天真的期望是它的工作方式类似于或类似于 CPP。我只能从直接继承的类中覆盖函数。

我希望你能给我一个提示让它工作或告诉我为什么它不能工作。先感谢您。

我尝试了以下修改:

这是我的 cpp 代码:

class Animal {
public:
    virtual std::string go(int n_times) = 0;
    virtual std::string name() { return "unknown"; }
};
class Dog : public Animal {
public:
    std::string go(int n_times) override {
        std::string result;
        for (int i=0; i<n_times; ++i)
            result += bark() + " ";
        return result;
    }
    virtual std::string name() { return "Dog"; }
    virtual std::string bark() { return "woof!"; }
};

class PyAnimal : public Animal {
public:
    using Animal::Animal; // Inherit constructors
    std::string go(int n_times) override { PYBIND11_OVERLOAD_PURE(std::string, Animal, go, n_times); }
    std::string name() override { PYBIND11_OVERLOAD(std::string, Animal, name, ); }
};
class PyDog : public Dog {
public:
    using Dog::Dog; // Inherit constructors
    std::string go(int n_times) override { PYBIND11_OVERLOAD(std::string, Dog, go, n_times); }
    std::string name() override { PYBIND11_OVERLOAD(std::string, Dog, name, ); }
    std::string bark() override { PYBIND11_OVERLOAD(std::string, Dog, bark, ); }
};

std::string call_go(Animal *animal) {
    return animal->go(3);
}

std::string call_bark(Dog *dog) {
    return dog->bark();
}



PYBIND11_MODULE(_MyTest, m)
{
    py::class_<Animal, PyAnimal /* <--- trampoline*/>(m, "Animal")
        .def(py::init<>())
        .def("go", &Animal::go);

    py::class_<Dog, Animal>(m, "Dog")
        .def(py::init<>())
        .def("go", &Dog::go)
        .def("bark", &Dog::bark);

    m.def("call_go", &call_go);
    m.def("call_bark", &call_bark);
}

这是我的python代码:

#!/usr/bin/env python3

import sys
from ATOM import _MyTest as test


def main(argv=None):
    print("check Dog")
    d = test.Dog()
    print(test.call_go(d))
    print(test.call_bark(d))

    class Cat(test.Animal):
        def go(self, n_times):
            return "meow! " * n_times

    print("check Cat")
    c = Cat()
    print(test.call_go(c))

    print("check Bello")
    class Bello(test.Dog):
        def go(self, n_times):
            return "grrrr! " * n_times

        def bark(self):
            return "grrrr! "

    b = Bello()
    print(test.call_go(b))
    print(test.call_bark(b))
    print(b.go(3))
    print(b.bark())

if __name__ == "__main__":
    sys.exit(main())

标签: pythonc++pybind11

解决方案


推荐阅读