简体   繁体   中英

override a C++ virtual function within Python with Boost.python?

I have a C++ class with a virtual method:

//C++ class A {

public:
    A() {};
    virtual int override_me(int a) {return 2*a;};
    int calculate(int a) { return this->override_me(a) ;}

};

What I would like to do is to expose this class to Python with Boost.python, inherit from this class in Python and have the correct overridden called:

#python:
class B(A):
   def override_me(self, a):
       return 5*a
b = B()
b.calculate(1) # should return 5 instead of 2

I'd like to do the same for pure virtual functions. I'm looking for a way to not create any wrapper class in C++ over the class A. Would that be possible ? If yes/ if no, how can I do it ?

You can provide a thin wrapper around your class that delegates the override_me method calls to boost::python -specific override function.

Derived class calculate calls simply call the parent class calculate method, so when they are called from Python, they call the C++ defined calculate method, but still allow override_me method to be overridden from Python:

#include <boost/python.hpp>
using namespace boost;
using namespace boost::python;

class A {

public:
    A() {};
    virtual int override_me(int a) {
        return 2*a;
    };
    virtual int calculate(int a) {
        return this->override_me(a);
    }
};

struct AWrap: A, public boost::python::wrapper<A> {
    AWrap() : A() {};
    int override_me(int a) override {
        if (override f = this->get_override("override_me")) {
            return this->get_override("override_me")(a);
        } else {
            return A::override_me(a);
        }
    };
    int calculate(int a) override {
        return A::calculate(a);
    }
};

BOOST_PYTHON_MODULE(my_lib)
{
      python::class_<AWrap, boost::noncopyable>("A", python::init<>())
      .def("override_me", &AWrap::override_me)
      .def("calculate", &AWrap::calculate);
}

int main() {}

g++ virtual_override.cpp -fPIC -shared -I/path/to/include/python3 -L/path/to/libpython3 -o my_lib.so -lpython3 -lboost_python3

Example:

This allows for non-pure cases, for example, when override_me isn't overridden, the default function is called:

import my_lib

class B(my_lib.A):
    pass
b = B()

print (b.calculate(1))

2

But virtual overrides are possible from Python:

import my_lib

class B(my_lib.A):
   def override_me(self, a):
       return 5*a
b = B()

print (b.calculate(1))

5

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM