0

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 ?

7
  • "not create any wrapper class in C++ over the class A" - how strong is the requirement? :-) Commented Aug 27, 2020 at 7:26
  • No strong requirement. If it is achievable, then its well and good for me Commented Aug 27, 2020 at 7:41
  • There is a standard way of exposing C++ classes to Python with boost::python, have you tried it? (I personally recommend pybind11 over boost::python, the two packages are very similar in spirit so ideas and techniques carry over). Commented Aug 27, 2020 at 8:09
  • this seems to be like what you want, but I could not make it work :-D Commented Aug 27, 2020 at 8:27
  • Why do you recomend pybind11 over boost @n.'pronouns'm. Commented Aug 27, 2020 at 9:11

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.