python - 带有 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。我只能从直接继承的类中覆盖函数。
我希望你能给我一个提示让它工作或告诉我为什么它不能工作。先感谢您。
我尝试了以下修改:
- 使用 PyDog 作为蹦床而不是 Animal --
py::class_<Dog, PyDog>(m, "Dog")
- 这通过在 python 代码中调用 print(test.call_go(d)) 导致错误,因为 d 不再是 Animal 类型。我不知道为什么,因为 PyDog 继承自 Animal。函数 bark() 正如预期的那样被覆盖了。
- 如果 python 类 Bello 从 test.Animal 而不是 test.Dog 继承,那么函数 go 会按预期被覆盖。
这是我的 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())
解决方案
推荐阅读
- c++ - 将另一个类的对象传递给当前类 C++ 的构造函数(不是成员初始化)
- python - Python & Simpy:模拟有限的吞吐量和网络拥塞
- mqtt - MQTT / Mosquitto 桥接器未经代理 ACL 授权
- python - Selenium Python - 如何让我的程序在特定元素出现时单击它?
- python - 从带有参数的 python 脚本调用 pytest
- python-3.x - 问题:使用 Azure 机器学习服务部署模型
- javascript - 标签不居中分组条形图小于 5
- javascript - Json response vue
- css - IE11 CSS hover rule for list item not triggered
- javascript - 如果类存在于另一个 div 中,则更改 div 的高度