在 boost.python 中使用时无法在我的摘要 class 中使用纯虚函数
Cannot use pure virtual functions in my abstract class when using it in boost.python
我正在尝试用我的 C++ 库扩展 Python,我 运行 遇到了这个特殊情况的一些问题:假设有一个抽象 class 叫做Shape
现在我想允许 Python 继承自 Shape 并基本上实现它自己的 Shape
,但也能够在 C++ 代码中使用 Shape 的一些现有实现。让我展示一些代码:
class Shape {
public:
virtual inline double get_area() const = 0;
};
太好了,现在假设有一个名为 Circle
.
的 C++ class
class Circle : public Shape {
public:
Circle() = default;
inline double get_area() const override { return 0.5; }
}
好的,让我们为 Shape
(版本 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();
}
};
然后这样定义形状:
class_<ShapeWrap, boost::noncopyable>("Shape")
.def("get_area", &Shape::get_area, &ShapeWrap::default_get_area));
好吧,现在这是一个问题,因为 Shape
是一个抽象 class 并且理所当然地它没有实现 get_area
(它是纯虚拟的)。好吧,我们把这些都划掉然后这样写怎么样?
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;
}
};
然后像这样定义 Shape
:
class_<ShapeWrap, boost::noncopyable>("Shape")
.def("get_area", pure_virtual(&ShapeWrap::get_area));
好的,这对于 Python 覆盖的对象来说工作得很好。但是,如果我在 Python 中创建一个 Circle
对象,它会给我以下错误:
Boost.Python.ArgumentError: Python argument types in
Shape.get_area(Circle)
did not match C++ signature:
get_area(ShapeWrap {lvalue})
get_area(ShapeWrap {lvalue})
现在,如果我将 Shape
class 中的 get_area
设置为 return 0.0 作为默认行为,所有这些都将得到修复,但我不想以这种方式编写我的 API 只是为了支持 Python,我希望在该功能不可用时有一个默认功能,而 return 0.0 仅适用于 Python因为抽象 classes 的概念在 Python 中并不以相同的方式存在,这很好,但是我会得到 Shape
作为抽象 class我的 C++ API 的其余部分。有什么办法吗?
感谢@llonesmiz,我意识到问题是包装函数被传递给了纯虚拟函数。以这种方式定义 ShapeWrapper
可以解决问题:
class_<ShapeWrap, boost::noncopyable>("Shape")
.def("get_area", pure_virtual(&Shape::get_area));
我正在尝试用我的 C++ 库扩展 Python,我 运行 遇到了这个特殊情况的一些问题:假设有一个抽象 class 叫做Shape
现在我想允许 Python 继承自 Shape 并基本上实现它自己的 Shape
,但也能够在 C++ 代码中使用 Shape 的一些现有实现。让我展示一些代码:
class Shape {
public:
virtual inline double get_area() const = 0;
};
太好了,现在假设有一个名为 Circle
.
class Circle : public Shape {
public:
Circle() = default;
inline double get_area() const override { return 0.5; }
}
好的,让我们为 Shape
(版本 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();
}
};
然后这样定义形状:
class_<ShapeWrap, boost::noncopyable>("Shape")
.def("get_area", &Shape::get_area, &ShapeWrap::default_get_area));
好吧,现在这是一个问题,因为 Shape
是一个抽象 class 并且理所当然地它没有实现 get_area
(它是纯虚拟的)。好吧,我们把这些都划掉然后这样写怎么样?
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;
}
};
然后像这样定义 Shape
:
class_<ShapeWrap, boost::noncopyable>("Shape")
.def("get_area", pure_virtual(&ShapeWrap::get_area));
好的,这对于 Python 覆盖的对象来说工作得很好。但是,如果我在 Python 中创建一个 Circle
对象,它会给我以下错误:
Boost.Python.ArgumentError: Python argument types in
Shape.get_area(Circle)
did not match C++ signature:
get_area(ShapeWrap {lvalue})
get_area(ShapeWrap {lvalue})
现在,如果我将 Shape
class 中的 get_area
设置为 return 0.0 作为默认行为,所有这些都将得到修复,但我不想以这种方式编写我的 API 只是为了支持 Python,我希望在该功能不可用时有一个默认功能,而 return 0.0 仅适用于 Python因为抽象 classes 的概念在 Python 中并不以相同的方式存在,这很好,但是我会得到 Shape
作为抽象 class我的 C++ API 的其余部分。有什么办法吗?
感谢@llonesmiz,我意识到问题是包装函数被传递给了纯虚拟函数。以这种方式定义 ShapeWrapper
可以解决问题:
class_<ShapeWrap, boost::noncopyable>("Shape")
.def("get_area", pure_virtual(&Shape::get_area));