Reputation: 355
I'm using Boost Python to provide a python interface to some classes in C++. I have found this situation that I'm not sure how to solve:
I have a class that has this member functions:
virtual void visit(const ReportClass r) = 0;
virtual void visit(const unsigned int category) = 0;
virtual void visit(const char* type) = 0;
virtual void visit(const char* name, const unsigned int id, const char &value ) = 0;
virtual void visit(const char* name, const unsigned int id, const unsigned short &value ) = 0;
virtual void visit(const char* name, const unsigned int id, const unsigned int &value ) = 0;
virtual void visit(const char* name, const unsigned int id, const MaskedAddr &value ) = 0;
virtual void visit(const char* name, const unsigned int id, const unsigned long long &value ) = 0;
I'm a bit lost on how to implement the python-boost part, I have seen how to proceed with virtual functions and overloaded functions but I don't know how to combine both.
And by the way, I see in the example that a virtual function returning an int (for example) should be implemented this way:
int f()
{
return this->get_override("f")();
}
In my case they do not return anything I guess I should implement them this way:
void f()
{
this->get_override("f")();
}
Is this correct?
Thanks in advance
Upvotes: 1
Views: 303
Reputation: 5309
If I understand your question correctly, you want to bind pure virtual (overloaded) methods to Python, so they can be overloaded from python. The tutorial you have already found, explains that in part. In your specific case, C++ and Python do not interplay well with the overloading. While C++ allows it, Python forbids. You cannot have two methods with the name f
in Python. What we will have to do is to diverge the python calls, so the user can implement the overriding from Python.
I'll write a smaller example, but you can abstract from that.
Let's start with the C++ plumbing. Your C++ bindings should look like this:
struct BaseWrap : Base, boost::python::wrapper<Base> {
int f() {
return this->get_override("__f1__")();
}
int f(int i) {
return this->get_override("__f2__")()
}
int f(const char* s) {
return this->get_override("__f3__")()
}
int f(const char* s, double d) {
return this->get_override("__f4__")()
}
};
//your module code will look like this
BOOST_PYTHON_MODULE(example) {
using namespace boost::python;
class_<BaseWrap, boost::noncopyable>("Base")
.def("f", pure_virtual(((int)(Base::*)())&Base::f))
.def("f", pure_virtual(((int)(Base::*)(int))&Base::f))
.def("f", pure_virtual(((int)(Base::*)(const char*))&Base::f))
.def("f", pure_virtual(((int)(Base::*)(const char*, double))&Base::f))
;
}
What did we do? When the Python side of the code calls f(<parameters>)
, we will resolve to the right overloaded method. This method will then call Python's __f1__
, __f2__
, etc, in which the meat of the method was really coded in, from Python.
To finalise the binding, in Python, you must inherit from example.Base
and implement __f1__
, __f2__
, __f3__
and __f4__
:
class Base(example.Base):
"""Throw here the documentation of Base - don't bother about the C++ stuff"""
def __init__(self,...):
pass
def __f1__(self):
"""Implementation of Base::f()"""
pass
def __f2__(self):
"""Implementation of Base::f(int)"""
pass
def __f3__(self):
"""Implementation of Base::f(const char*)"""
pass
def __f4__(self):
"""Implementation of Base::f(const char*, double)"""
pass
Upvotes: 1
Reputation: 17444
Let's take the easy question first: You can always "return this->get_override("f")();", even if the return type is void. Actually, in such wrapper code, I find that even the better choice, because if suddenly the wrapped function returns something, you will get a compile error!
Now the difficult question: How to mix virtual and overloaded functions here. I would circumvent this problem using the template method pattern. The idea is to simply provide a public, nonvirtual function that calls a private virtual function. Optionally, you can make the virtual one protected in order to allow extension instead of overriding. Further, in the nonvirtual one, you can verify pre/post conditions that the derived classes must fulfill or validate parameters (e.g. assert(name);).
Upvotes: 1