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

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

错误原因解释

  1. 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。

  2. ImportError: generic_type: type "FuelCostStep" does not have a non-default holder type while its base "EdgeAttributePipelineStep" does:
    派生类未明确指定和基类一致的std::shared_ptr holder,PyBind11检测到基类用了自定义holder,而派生类用默认holder,触发类型不兼容错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 22:55:37