PyBind11实现带继承类的共享指针向量绑定遇错求助
正确实现PyBind11绑定的步骤
核心问题分析
你遇到的两个错误本质是纯虚基类与派生类的holder类型不统一:
- 纯虚基类必须用
std::shared_ptr作为holder(因为要处理多态对象的生命周期),但派生类默认使用PyBind11的默认holder,导致类型不兼容 - Trampoline类是给Python继承C++纯虚类用的,必须和基类的holder绑定逻辑配合
步骤1:确保C++类定义符合要求
以下是匹配需求的C++类框架(可对应你的实际代码):
#include <memory> #include <vector> #include <string> // 纯虚基类 class EdgeAttributePipelineStep { public: virtual ~EdgeAttributePipelineStep() = default; virtual double calculate(double value) const = 0; virtual std::string name() const = 0; }; // 派生类:FuelCostStep class FuelCostStep : public EdgeAttributePipelineStep { private: double rate_; public: FuelCostStep(double rate) : rate_(rate) {} double calculate(double value) const override { return value * rate_; } std::string name() const override { return "FuelCostStep"; } }; // 派生类:HireCostStep class HireCostStep : public EdgeAttributePipelineStep { private: double fee_; public: HireCostStep(double fee) : fee_(fee) {} double calculate(double value) const override { return value + fee_; } std::string name() const override { return "HireCostStep"; } }; // Pipeline类 class EdgeAttributePipeline { private: std::vector<std::shared_ptr<EdgeAttributePipelineStep>> steps_; public: explicit EdgeAttributePipeline(std::vector<std::shared_ptr<EdgeAttributePipelineStep>> steps) : steps_(std::move(steps)) {} double run(double initial_value) const { double result = initial_value; for (const auto& step : steps_) { result = step->calculate(result); } return result; } };
步骤2:编写正确的PyBind11绑定代码
关键要点:
- 基类绑定必须指定
std::shared_ptr<EdgeAttributePipelineStep>作为holder - 派生类必须继承基类的holder设置,不能使用默认holder
- Trampoline类用于支持Python继承基类(即使暂时不需要,也要绑定以保证多态逻辑正常)
#include <pybind11/pybind11.h> #include <pybind11/stl.h> #include <memory> namespace py = pybind11; // Trampoline类:用于Python继承C++纯虚基类 class EdgeAttributePipelineStepTrampoline : public EdgeAttributePipelineStep { public: using EdgeAttributePipelineStep::EdgeAttributePipelineStep; double calculate(double value) const override { PYBIND11_OVERRIDE_PURE( double, EdgeAttributePipelineStep, calculate, value ); } std::string name() const override { PYBIND11_OVERRIDE_PURE( std::string, EdgeAttributePipelineStep, name ); } }; PYBIND11_MODULE(edge_pipeline, m) { // 1. 绑定纯虚基类,指定holder为std::shared_ptr py::class_<EdgeAttributePipelineStep, EdgeAttributePipelineStepTrampoline, std::shared_ptr<EdgeAttributePipelineStep>>(m, "EdgeAttributePipelineStep") .def(py::init<>()); // 2. 绑定派生类FuelCostStep,指定相同holder类型 py::class_<FuelCostStep, EdgeAttributePipelineStep, std::shared_ptr<FuelCostStep>>(m, "FuelCostStep") .def(py::init<double>()); // 3. 绑定派生类HireCostStep,同样指定holder py::class_<HireCostStep, EdgeAttributePipelineStep, std::shared_ptr<HireCostStep>>(m, "HireCostStep") .def(py::init<double>()); // 4. 绑定Pipeline类,PyBind11自动处理std::vector<std::shared_ptr>的转换 py::class_<EdgeAttributePipeline>(m, "EdgeAttributePipeline") .def(py::init<const std::vector<std::shared_ptr<EdgeAttributePipelineStep>>&>()) .def("run", &EdgeAttributePipeline::run); }
步骤3:Python测试代码
现在可以正常运行你想要的代码:
import edge_pipeline pipeline = edge_pipeline.EdgeAttributePipeline([ edge_pipeline.FuelCostStep(10), edge_pipeline.HireCostStep(10) ]) # 测试运行 print(pipeline.run(5)) # 输出:60
错误原因解释
RuntimeError: Unable to load a custom holder type from a default-holder instance:
基类绑定用了std::shared_ptr作为holder,但派生类用了默认holder(如std::unique_ptr或PyBind11内部holder),导致派生类对象无法转换为基类的std::shared_ptr。ImportError: generic_type: type "FuelCostStep" does not have a non-default holder type while its base "EdgeAttributePipelineStep" does:
派生类未明确指定和基类一致的std::shared_ptrholder,PyBind11检测到基类用了自定义holder,而派生类用默认holder,触发类型不兼容错误。
内容的提问来源于stack exchange,提问作者Tom McLean
相关产品推荐
相关产品推荐

