pybind11:不向下转换为非多态基类

问题描述

当多态类继承自非多态基类时,我发现 pybind11 有一些奇怪的行为。考虑:

struct Base {
    Base() { id = (long int)this; }
    int get_id() const { return id; }
    int get_bthis() const { return (long int)this; }
    long int id;
};
struct poly: public Base {
    virtual long int polymethod() { return get_id(); }
    long int get_pthis(){ return (long int)this;}
};

随着pybind

#include <pybind11/pybind11.h>
namespace py = pybind11;

PYBIND11_MODULE(example,m) {
    py::class_<Base>(m,"Base")
        .def("get_id",&Base::get_id)
        .def("get_bthis",&Base::get_bthis);
    py::class_<poly,Base>(m,"poly")
        .def("get_pthis",&poly::get_pthis)
        .def("polymethod",&poly::polymethod);

    m.def("make_base",[]() { return new Base();});
    m.def("make_poly",[]() { return new poly();});
}

看起来 poly->Base 指针在蹦床中没有向上转换,因为 example.make_poly().get_id() 返回垃圾this 指针没有被 vtable 正确偏移:

>>> import example
>>> base = example.make_base()
>>> base.get_id() # Ok
7038096
>>> base.get_bthis() # Ok
7038096
>>> poly = example.make_poly()
>>> poly.get_pthis() # Ok
7046720
>>> virt.polymethod() # Ok
7046728
>>> poly.get_bthis() # BUGGY,get_bthis() should be same as polymethod()
7046720
>>> poly.get_id() # BUGGY,but can crash!
-1116853264

本机 C++ 中的等效项正确考虑了基类偏移量:

#include <iostream>
int main(int argc,char** argv) {

    auto base = new Base();
    std::cout << "base->get_this():" << base->get_this() << std::endl;
    std::cout << "base->get_id():" << base->get_id() << std::endl;

    auto virt = new poly();
    std::cout << "poly->get_bthis():" << poly->get_bthis() << std::endl;
    std::cout << "poly->get_id():" << poly->get_id() << std::endl;
    std::cout << "poly->get_pthis():" << poly->get_pthis() << std::endl;
    std::cout << "poly->polymethod():" << poly->polymethod() << std::endl;

    return 0;
}

印刷品

base->get_bthis():14856208
base->get_id():14856208

poly->get_bthis():14856248
poly->get_id():14856248
poly->get_pthis():14856240
poly->polymethod():14856248

我最怀疑 py::class_<poly,"poly"),但没有它我无法使用 poly::get_id。这是一个 pybind 错误,还是我没有正确声明我的类继承?使 Base 也多态(例如通过添加 virtual ~Base())使一切正常。

或者这最终归结为静态调度还是动态调度;后者在 C++ 中“需要”多态基类?

编辑:此问题的先前版本提到了“虚拟类”,而不是“多态类”的正确术语。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)