[英]Polymorphism and pybind11
I have a strange behaviour with pybind11 when I want to use C++ polymorphism in Python. 当我想在Python中使用C ++多态时,我对pybind11有一个奇怪的行为。 Here is a simple example of my problem: 这是我的问题的一个简单示例:
import polymorphism as plm
a = plm.mylist()
print(a)
a[0].print()
a[1].print()
The output of this script is 这个脚本的输出是
[MyBase, MyDerived] [MyBase,MyDerived]
MyBase MyBase
MyBase MyBase
but the expected output is 但预期的产出是
[MyBase, MyDerived] [MyBase,MyDerived]
MyBase MyBase
MyDerived MyDerived
because mylist return a std::vector which contains an instance of a derived class (MyDerived) as a second member. 因为mylist返回一个std :: vector,它包含一个派生类(MyDerived)的实例作为第二个成员。 The strange thing is that MyDerived is recognized when I print the list as a whole. 奇怪的是,当我打印整个列表时,MyDerived被识别出来。
Here is the header file of the C++ code: 这是C ++代码的头文件:
/* polymorphism.hpp */
#ifndef POLYMORPHISM_HPP
#define POLYMORPHISM_HPP
#include <vector>
class MyBase
{
public:
virtual void print() const;
};
class MyDerived : public MyBase
{
public:
virtual void print() const;
};
std::vector<MyBase*> mylist();
#endif
And here is the cpp file: 这是cpp文件:
#include "polymorphism.hpp"
#include <iostream>
#include <pybind11/stl.h>
#include <pybind11/pybind11.h>
void MyBase::print() const
{ std::cout << "MyBase" << std::endl; }
void MyDerived::print() const
{ std::cout << "MyDerived" << std::endl; }
std::vector<MyBase*> mylist()
{
std::vector<MyBase*> list(2);
list[0] = new MyBase();
list[1] = new MyDerived();
return list;
}
PYBIND11_MODULE(polymorphism, m)
{
pybind11::class_<MyBase>(m, "MyBase")
.def(pybind11::init<>())
.def("print", &MyBase::print)
.def("__repr__", [](const MyBase &a) { return "MyBase"; });
pybind11::class_<MyDerived, MyBase>(m, "MyDerived")
.def(pybind11::init<>())
.def("print", &MyDerived::print)
.def("__repr__", [](const MyDerived &a) { return "MyDerived"; });
m.def("mylist", &mylist, "return a list");
}
EDIT: more surprisingly, when I remove the binding of "print" for MyDerived, I get the following error message 编辑:更令人惊讶的是,当我删除MyDerived的“打印”绑定时,我收到以下错误消息
[MyBase, MyDerived] [MyBase,MyDerived]
MyBase MyBase
Traceback (most recent call last): Traceback(最近一次调用最后一次):
File "test.py", line 8, in 文件“test.py”,第8行,in
a[1].print() 一个[1] .PRINT()
AttributeError: 'polymorphism.MyDerived' object has no attribute 'print' AttributeError:'polymorphism.MyDerived'对象没有属性'print'
This message seems to mean that MyDerived is well recognized while the wrong version of print is called (if I understand well). 此消息似乎意味着MyDerived在调用错误版本的打印时得到了充分认可(如果我理解的话)。
EDIT 2: here is a version using trampoline classes. 编辑2:这是一个使用蹦床类的版本。 However, this version leads to the same wrong output. 但是,此版本导致相同的错误输出。
/* polymorphism.hpp */
#ifndef POLYMORPHISM_HPP
#define POLYMORPHISM_HPP
#include <vector>
#include <pybind11/stl.h>
#include <pybind11/pybind11.h>
class MyBase
{
public:
virtual void print() const;
};
class MyDerived : public MyBase
{
public:
virtual void print() const;
};
std::vector<MyBase*> mylist();
class PyMyBase : public MyBase
{
public:
using MyBase::MyBase; // Inherit constructors
void print() const override { PYBIND11_OVERLOAD(void, MyBase, print ); }
};
class PyMyDerived : public MyDerived
{
public:
using MyDerived::MyDerived; // Inherit constructors
void print() const override { PYBIND11_OVERLOAD(void, MyDerived, print);}
};
#endif
Here is the corresponding cpp file: 这是相应的cpp文件:
/* polymorphism.cpp */
#include "polymorphism.hpp"
#include <iostream>
void MyBase::print() const
{ std::cout << "MyBase" << std::endl; }
void MyDerived::print() const
{ std::cout << "MyDerived" << std::endl; }
std::vector<MyBase*> mylist()
{
std::vector<MyBase*> list(2);
list[0] = new MyBase();
list[1] = new MyDerived();
return list;
}
PYBIND11_MODULE(polymorphism, m)
{
pybind11::class_<MyBase, PyMyBase>(m, "MyBase")
.def(pybind11::init<>())
.def("print", &MyBase::print)
.def("__repr__", [](const MyBase &a) { return "MyBase"; });
pybind11::class_<MyDerived, PyMyDerived>(m, "MyDerived")
.def(pybind11::init<>())
.def("print", &MyDerived::print)
.def("__repr__", [](const MyDerived &a) { return "MyDerived"; });
m.def("mylist", &mylist, "return a list");
}
I dont know why, but pybind11
seems to have a problem with the raw pointers in mylist()
. 我不知道为什么,但是pybind11
似乎在mylist()
的原始指针有问题。 The example works correctly if you change the return type to vector<unique_ptr<MyBase>>
. 如果将返回类型更改为vector<unique_ptr<MyBase>>
则该示例可正常工作。 The following example compiles to a python module example
and produces the expected output. 以下示例编译为python模块example
并生成预期输出。
example.cpp: example.cpp:
#include <pybind11/stl.h>
#include <pybind11/pybind11.h>
#include <iostream>
#include <memory>
#include <vector>
class MyBase {
public:
virtual void print() const {
std::cout << "MyBase::print()" << std::endl;
}
};
class MyDerived : public MyBase {
public:
virtual void print() const override {
std::cout << "MyDerived::print()" << std::endl;
}
};
std::vector<std::unique_ptr<MyBase>> mylist() {
std::vector<std::unique_ptr<MyBase>> v;
v.push_back(std::make_unique<MyBase>());
v.push_back(std::make_unique<MyDerived>());
return v;
}
PYBIND11_MODULE(example, m) {
pybind11::class_<MyBase>(m, "MyBase")
.def(pybind11::init<>())
.def("print", &MyBase::print)
.def("__repr__", [](MyBase const&) { return "MyBase"; });
pybind11::class_<MyDerived>(m, "MyDerived")
.def(pybind11::init<>())
.def("print", &MyDerived::print)
.def("__repr__", [](MyDerived const&) { return "MyDerived"; });
m.def("mylist", &mylist, "returns a list");
}
python shell: python shell:
>>> import example
>>> l = example.mylist()
>>> l[0].print()
MyBase::print()
>>> l[1].print()
MyDerived::print()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.