首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多态性与pybind11

多态性与pybind11
EN

Stack Overflow用户
提问于 2018-04-03 15:37:05
回答 1查看 875关注 0票数 7

当我想在Python中使用C++多态性时,我对C++有一种奇怪的行为。下面是我的问题的一个简单例子:

代码语言:javascript
复制
import polymorphism as plm

a = plm.mylist()

print(a)

a[0].print()
a[1].print()

此脚本的输出是

MyBase,MyDerived MyBase MyBase

但预期的产出是

MyBase,MyDerived MyBase MyDerived

因为mylist返回一个std::vector,它包含派生类(MyDerived)的一个实例作为第二个成员。奇怪的是,当我作为一个整体打印列表时,MyDerived就被识别了。

下面是C++代码的头文件:

代码语言:javascript
复制
/* 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

以下是cpp文件:

代码语言:javascript
复制
#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");
}

编辑:更令人惊讶的是,当我删除MyDerived的"print“绑定时,我会得到以下错误消息

MyBase,MyDerived MyBase 回溯(最近一次调用): 文件"test.py",第8行 A1.() AttributeError:'polymorphism.MyDerived‘对象没有属性'print’

这个消息似乎意味着MyDerived被很好地识别,而错误的打印版本被调用(如果我理解的话)。

编辑2:这是一个使用蹦床类的版本。但是,这个版本会导致同样的错误输出。

代码语言:javascript
复制
/* 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

下面是对应的cpp文件:

代码语言:javascript
复制
/* 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");
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-04 06:49:54

我不知道为什么,但是pybind11似乎对mylist()中的原始指针有问题。如果将返回类型更改为vector<unique_ptr<MyBase>>,则示例将正确工作。下面的示例编译为python模块example并生成预期的输出。

example.cpp:

代码语言:javascript
复制
#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外壳:

代码语言:javascript
复制
>>> import example
>>> l = example.mylist()
>>> l[0].print()
MyBase::print()
>>> l[1].print()
MyDerived::print()
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49633990

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档