You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

pybind11中通过shared_ptr获取Python实现的抽象类实例后,调用纯虚函数未触发Python重写实现的问题

pybind11中通过shared_ptr获取Python实现的抽象类实例后,调用纯虚函数未触发Python重写实现的问题

我之前碰到过几乎一模一样的问题,你的代码核心问题出在抽象基类的Python包装类没有正确定义构造函数,导致pybind11没法为Python子类实例创建对应的C++包装对象,最终调用虚函数时无法路由到Python的重写实现。

问题根源分析

你的ScriptScriptFactory都是抽象类,本身没有可直接调用的构造函数。你定义的PyScriptPyScriptFactory用了using Script::Script;using ScriptFactory::ScriptFactory;来尝试继承构造函数,但抽象类的构造函数是没法被直接继承和调用的——这就导致这两个包装类实际上没有可用的默认构造函数。

当Python返回MyScript实例给C时,pybind11需要创建一个PyScript实例作为底层C对象来关联Python对象,但因为PyScript没有合法的构造函数,这个关联过程失败了。最终C++拿到的shared_ptr<Script>指向的是一个未正确初始化、没有绑定到Python对象的实例,调用init()时自然就触发了纯虚函数的运行时错误。

解决方案

修改C++中的PyScriptPyScriptFactory定义,为它们添加默认构造函数,替换原来无效的构造函数继承语句:

// 修改PyScript定义
struct PyScript : public Script {
    // 替换 using Script::Script; 为默认构造函数
    PyScript() = default;
    void init() override {
        PYBIND11_OVERRIDE_PURE(
            void, Script, init
        );
    }
};

// 修改PyScriptFactory定义
struct PyScriptFactory : ScriptFactory {
    // 替换 using ScriptFactory::ScriptFactory; 为默认构造函数
    PyScriptFactory() = default;
    std::shared_ptr<Script> getScript(const std::string& type) override {
        PYBIND11_OVERRIDE_PURE(
            std::shared_ptr<Script>, ScriptFactory, getScript, type
        );
    }
};

修改后的效果

添加默认构造函数后,pybind11可以正常创建PyScriptPyScriptFactory的实例,这些实例会正确绑定到Python侧的子类对象(MyScriptMyFactory)。当C++调用script->init()时,会通过PyScript::init()中的PYBIND11_OVERRIDE_PURE宏路由到Python的MyScript.init()方法,就能输出你预期的Hello, world!了。

另外补充一句:你的Python代码里不存在对象提前被垃圾回收的问题——Container持有scriptshared_ptr,只要my_cont对象存在,Python的MyScript实例就不会被回收,所以核心问题还是在C++包装类的构造函数上。

内容来源于stack exchange

火山引擎 最新活动