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

使用pybind11实现C++多态时Python端出现异常行为求助

解决pybind11中C++多态在std::vector里的方法调用异常问题

我来帮你搞定这个多态调用的坑!你遇到的问题核心原因是对象切片(Object Slicing):当你把MyDerived对象直接存入std::vector<MyBase>时,容器只会保存基类MyBase的部分,派生类特有的数据和虚函数表都会被“切掉”——哪怕你以为存的是MyDerived实例,实际调用print()时执行的还是基类的版本。

下面给你具体的修复步骤:

1. 修改C++侧的容器类型

把std::vector<MyBase>改成存储基类的智能指针,比如std::vector<std::unique_ptr<MyBase>>或者std::vector<std::shared_ptr<MyBase>>,这样才能真正保留派生类的多态特性,避免切片。

示例C++代码片段:

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
#include <memory>
#include <iostream>

class MyBase {
public:
    virtual ~MyBase() = default;
    virtual void print() const {
        std::cout << "MyBase" << std::endl;
    }
    virtual std::string type_name() const {
        return "MyBase";
    }
};

class MyDerived : public MyBase {
public:
    void print() const override {
        std::cout << "MyDerived" << std::endl;
    }
    std::string type_name() const override {
        return "MyDerived";
    }
};

std::vector<std::unique_ptr<MyBase>> mylist() {
    std::vector<std::unique_ptr<MyBase>> vec;
    vec.emplace_back(std::make_unique<MyBase>());
    vec.emplace_back(std::make_unique<MyDerived>());
    return vec;
}

namespace py = pybind11;

PYBIND11_MODULE(polymorphism, m) {
    // 绑定基类时指定智能指针作为持有者
    py::class_<MyBase, std::unique_ptr<MyBase, py::nodelete>>(m, "MyBase")
        .def(py::init<>())
        .def("print", &MyBase::print)
        .def("__repr__", &MyBase::type_name);

    // 派生类绑定要继承基类的类型和持有者
    py::class_<MyDerived, MyBase, std::unique_ptr<MyDerived, py::nodelete>>(m, "MyDerived")
        .def(py::init<>());

    m.def("mylist", &mylist);
}

2. 关键绑定细节说明

  • 绑定基类时,std::unique_ptr<MyBase, py::nodelete>是核心:py::nodelete告诉pybind11不要自动删除对象,因为智能指针已经接管了生命周期管理。
  • 派生类绑定必须明确继承基类的类型和持有者,这样pybind11才能正确识别多态关系,在Python侧正确派发虚函数调用。

3. 验证Python脚本

运行你的原Python代码:

import polymorphism as plm
a = plm.mylist()
print(a)
a[0].print()
a[1].print()

现在输出就会完全符合预期:

[MyBase, MyDerived]
MyBase
MyDerived

补充一句:如果之前你的mylist返回的是std::vector<MyBase>,哪怕构造时传入MyDerived,也会触发切片——派生类的虚表被覆盖,所以虚函数print()会执行基类逻辑。用智能指针容器是C++保存多态对象的标准操作,配合pybind11的正确绑定就能完美解决这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:19:17