Reputation: 3077
I'm trying to extend Python with my C++ library and I'm running into a few issues with this particular case: Let's say there is an abstract class called Shape
now I want to allow Python to inherit from Shape and basically implement its own Shape
, but also be able to use some existing implementations of Shape in the C++ code. Let me show some code:
class Shape {
public:
virtual inline double get_area() const = 0;
};
Great, now let's say there is a C++ class called Circle
.
class Circle : public Shape {
public:
Circle() = default;
inline double get_area() const override { return 0.5; }
}
Okay, let's write a wrapper for Shape
(version 1):
struct ShapeWrap : public Shape, public wrapper<Shape>{
inline double get_area() const override {
if (auto py_func = this->get_override("get")) return py_func();
return Shape::get_area();
}
inline double default_get_area() const {
return this->Shape::get_area();
}
};
and then define Shape this way:
class_<ShapeWrap, boost::noncopyable>("Shape")
.def("get_area", &Shape::get_area, &ShapeWrap::default_get_area));
Okay, now this is a problem because Shape
is an abstract class and rightfully so it doesn't implement get_area
(it's pure virtual). Alright, how about we scratch all of this and write it this way?
struct ShapeWrap : public Shape, public wrapper<Shape>{
inline double get_area() const override {
if (auto py_func = this->get_override("get")) return py_func();
return 0.0;
}
};
and then define Shape
like this:
class_<ShapeWrap, boost::noncopyable>("Shape")
.def("get_area", pure_virtual(&ShapeWrap::get_area));
Okay, so that works perfectly fine for the objects that Python overrides. However, if I create a Circle
object within Python, it would give me the following error:
Boost.Python.ArgumentError: Python argument types in
Shape.get_area(Circle)
did not match C++ signature:
get_area(ShapeWrap {lvalue})
get_area(ShapeWrap {lvalue})
Now, all of this would be fixed IF I make get_area
in the Shape
class to return 0.0 as a default behavior but I don't want to write my API that way just to support Python, I'd like to have a default function for when the function isn't available and return 0.0 ONLY for Python because the notion of abstract classes doesn't exist in the same way in Python and that's fine but then I'll get to have Shape
as an abstract class for the rest of my C++ API. Is there any way to do this?
Upvotes: 1
Views: 259
Reputation: 3077
Thanks to @llonesmiz, I realized the issue was that the wrappers function was passed to the pure virtual's function. Defining ShapeWrapper
this way would resolve the issue:
class_<ShapeWrap, boost::noncopyable>("Shape")
.def("get_area", pure_virtual(&Shape::get_area));
Upvotes: 2