[Python] Overriding C++ class virtual methods in Pybind11 with trampoline class - but still...

Discussão em 'Python' iniciado por Stack, Agosto 18, 2025.

  1. Stack

    Stack Membro Participativo

    I'm implementing a Pybind11 module, and I'm exposing a C++ class to Python that it's meant to be subclassed. I'm following what's described in here (https://pybind11.readthedocs.io/en/stable/advanced/classes.html) and below is the code for the C++ base and trampoline class.

    class CollisionResponse {
    public:
    CollisionResponse() : _tag1(0), _tag2(1) {}
    virtual ~CollisionResponse() = default;
    virtual void onStart() const {
    std::cout << "base called\n";
    }

    int getTag1() const;
    int getTag2() const;
    protected:
    int _tag1;
    int _tag2;
    };


    class PyCollisionResponse : public CollisionResponse {
    public:
    using CollisionResponse::CollisionResponse;

    void onStart() const override {

    PYBIND11_OVERRIDE(
    void, // Return type
    CollisionResponse, // Parent class
    onStart // Name of function in C++
    );

    }
    };


    Below is how I expose the class to Python:

    py::class_<CollisionResponse, PyCollisionResponse,
    std::shared_ptr<CollisionResponse>>(m, "CollisionResponse")
    .def(py::init<>())
    .def("onStart", &CollisionResponse::eek:nStart);


    Now I have a C++ object which holds a map of CollisionResponse objects, that are passed from Python via the addResponse method:

    class CollisionEngine:
    ...
    void addResponse(std::shared_ptr<CollisionResponse> response) {
    _response.insert({std::make_pair(response->getTag1(), response->getTag2()), response});

    }

    std::unordered_map<std::pair<int, int>, std::shared_ptr<CollisionResponse>> _response;



    Last but not least is the Python code:

    class TestCollision(example.CollisionResponse):

    def onStart(self):
    print('derived class')
    ...

    cr = CollisionResponse()
    cr.addResponse(TestCollision())


    Now, in the CollisionEngine class, I have a method that calls the onStart method from the CollisionResponse objects stored in _response. However, no matter what happens, the base implementation always get called. In debug, I can see that the PyCollisionResponse::eek:nStart is called, but then execution goes inside the CollisionResponse::eek:nStart, and not in the Python TestCollision.onStart.

    I'm really struggling figuring out what's wrong!

    Continue reading...

Compartilhe esta Página