You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pybind11绑定含虚函数的C++类出现未定义行为问题求助

解决pybind11绑定带虚函数子类时父类成员访问的垃圾值问题

核心修复方案

将父类vec3的成员绑定方式从def_readwrite改为使用def_property配合lambda getter/setter,避免直接使用成员指针导致的偏移计算错误。

问题根源

当Point类包含虚函数时,其内存布局首地址会被虚表指针(vptr)占据,而vec3作为基类的成员是在vptr之后的内存区域。pybind11的def_readwrite使用的是成员指针,该指针的偏移是相对于vec3实例的起始地址计算的,但通过Point实例访问时,pybind11错误地从Point实例的首地址(即vptr位置)开始应用这个偏移,导致读取到虚表指针的垃圾值。而lambda getter/setter是通过对象引用访问成员,编译器会自动计算Point实例中vec3子对象的正确偏移,从而访问到正确的成员值。

修正后的完整代码

C++绑定代码

#include <pybind11/pybind11.h>

namespace py = pybind11;

struct vec3
{
    double t, x, y;
    vec3(double t, double x, double y) : t(t), x(x), y(y) {}
};

class Point : public vec3
{
public:
    Point(double t, double x, double y) : vec3(t, x, y) {}
    virtual void test() {}
};

// 修正trampoline类:非纯虚函数使用PYBIND11_OVERRIDE
class PyPoint : public Point
{
public:
    using Point::Point;
    void test() override { PYBIND11_OVERRIDE(void, Point, test, ); }
};

PYBIND11_MODULE(relatpy, m)
{
    py::class_<vec3>(m, "vec3")
        .def(py::init<double, double, double>())
        // 用lambda getter/setter替代直接成员指针
        .def_property("t", 
            [](const vec3& v) { return v.t; }, 
            [](vec3& v, double val) { v.t = val; })
        .def_property("x", 
            [](const vec3& v) { return v.x; }, 
            [](vec3& v, double val) { v.x = val; })
        .def_property("y", 
            [](const vec3& v) { return v.y; }, 
            [](vec3& v, double val) { v.y = val; });

    py::class_<Point, vec3, PyPoint>(m, "Point")
        .def(py::init<double, double, double>())
        .def("test", &Point::test);
}

Python测试代码

from relatpy import *

p = Point(1, 2, 3)
print(p.t)  # 输出1
print(p.x)  # 输出2
print(p.y)  # 输出3

额外说明

之前的trampoline类使用了PYBIND11_OVERRIDE_PURE,但test函数并非纯虚函数,需改为PYBIND11_OVERRIDE(注意末尾的逗号和空参数,对应无参数的虚函数),不过这不是导致垃圾值的核心原因,核心问题还是成员指针的偏移计算错误。

内容的提问来源于stack exchange,提问作者catmousedog

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:03:21