admin管理员组

文章数量:1391943

When creating a Python-derived class from a C++ base class (with a pure virtual function) via a callback, the Python override is not invoked. Instead, the program attempts to call the pure virtual function (A::go), resulting in a runtime error and segmentation fault.

Expected Behavior: The overridden Python method (e.g., PyDerivedA.go) should be called, producing the expected output (e.g., "PyDerivedA go called!").

Actual Behavior: The callback returns an instance of the Python-derived class, but due to improper conversion, the object loses its Python override bindings. When MyRun::Run is executed, it calls the pure virtual function A::go, triggering a runtime error and segmentation fault.

#include <pybind11/pybind11.h>
#include <pybind11/functional.h>  // 支持 std::function 类型
#include <memory>
#include <unordered_map>
#include <iostream>
#include <string>
#include <functional>
namespace py = pybind11;



class A {
public:
    A() { std::cout << "A" << std::endl; }
    virtual void go() = 0;
    virtual ~A()=default;
};
using CreationEvaluatorCallback = std::function<std::shared_ptr<A>(const std::string&)>;
class PyA : public A {
public:
    using A::A;
    void go() override {
        PYBIND11_OVERLOAD_PURE(
            void,  // 返回类型
            A,     // 父类
            go     // 方法名
        );
    }
};


class MyFactory {
public:
    static MyFactory& Instance() {
        static MyFactory instance; // C++11 保证局部静态变量线程安全
        return instance;
    }
    void Registry(const std::string &name, CreationEvaluatorCallback callback) {
        callback_registry_[name] = callback;
    }

    std::shared_ptr<A> Create(const std::string &evaluator_name) {
        auto iter = callback_registry_.find(evaluator_name);
        if (iter != callback_registry_.end()) {
            return iter->second(evaluator_name);
        }
        // 如果未找到对应的回调,可根据需要返回 nullptr 或抛出异常
        return nullptr;
    }

private:
    MyFactory() = default;
    ~MyFactory() = default;

    // 禁用拷贝构造和赋值运算符
    MyFactory(const MyFactory&) = delete;
    MyFactory& operator=(const MyFactory&) = delete;

    std::unordered_map<std::string, CreationEvaluatorCallback> callback_registry_;
};

class MyRun {
public:
    MyRun(){}
    ~MyRun(){}
    void Run(const std::string &evaluator_name){
        auto eval = MyFactory::Instance().Create(evaluator_name);
        eval->go();
    }
};


PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 包装 MyFactory 和 MyRun 示例";

    py::class_<A, PyA, std::shared_ptr<A>>(m, "A")
        .def(py::init<>())
        .def("go", &A::go);

    py::class_<MyFactory, std::unique_ptr<MyFactory, py::nodelete>>(m, "MyFactory")
        .def_static("instance", &MyFactory::Instance, py::return_value_policy::reference)
        .def("registry", &MyFactory::Registry)
        .def("create", &MyFactory::Create);

    // 包装 MyRun
    py::class_<MyRun>(m, "MyRun")
        .def(py::init<>())
        .def("run", &MyRun::Run);
}
import example
class PyDerivedA(example.A):
    def __init__(self):
        super().__init__()
        print("111111111111111111")
        
    def go(self):
        print("PyDerivedA go called!")


def create_derived(name):
    return PyDerivedA()

factory = example.MyFactory.instance()
factory.registry("derived", create_derived)


runner = example.MyRun()
runner.run("derived")  # 输出 "PyDerivedA go called!"


Traceback (most recent call last):
  File "/home/mi/fc4tdisk/code/pybind11/build/test.py", line 19, in <module>
    runner.run("derived")  # 输出 "PyDerivedA go called!"
RuntimeError: Tried to call pure virtual function "A::go"

本文标签: