使用Boost::Python封装纯虚拟函数

Wrapping the pure virtual function using Boost::Python

本文关键字:虚拟 函数 Python Boost 使用 封装      更新时间:2023-10-16

我现在正在学习使用Boost::Python向Python公开c++类,并编写了以下代码。

编译代码是可以的。但是当我从Python端导入代码时,它显示了以下错误:

追踪(最近一次通话):中的文件"test4.py",第1行

import shape;

导入错误:/home/ruofan/Boost/Class/shape.so:未定义符号:_ZTI7多边形

我该如何解决这个问题?

#include <iostream>
#include <boost/python.hpp>
using namespace boost::python;
using namespace std;
class Polygon {
  protected:
    int width, height;
  public:
    Polygon (int a, int b) : width(a), height(b) {}
    virtual int area (void) =0;
    void printarea()
      { cout << this->area() << 'n'; }
    virtual ~Polygon(); 
};
class Rectangle: public Polygon {
  public:
    Rectangle(int a,int b) : Polygon(a,b) {}
    int area()
      { return width*height; }
    virtual ~Rectangle();
};
class Triangle: public Polygon {
  public:
    Triangle(int a,int b) : Polygon(a,b) {}
    int area()
      { return width*height/2; }
    virtual ~Triangle();
};
struct BaseWrap : Polygon, wrapper<Polygon> {
  BaseWrap() : Polygon(0,0){}
  int area(){
        return this->get_override("area")();
  }
};

BOOST_PYTHON_MODULE(shape){
  class_<BaseWrap, boost::noncopyable>("Polygon")
    .def("area", pure_virtual(&Polygon::area));
}

问题是声明了非纯虚拟函数,但从未定义。这导致库具有对类"typeinfo:"的未定义引用

$ c++filt c++filt _ZTI7Polygon
typeinfo for Polygon

在这种特殊情况下,从来没有定义析构函数:

class Polygon {
  ...
  public:
    ...
    virtual ~Polygon(); // Declared, but never defined.
};

要解决此问题,请定义Polygyon析构函数:

class Polygon {
  ...
  public:
    ...
    virtual ~Polygon() = default;
};

RectangleTriangle类型也存在相同的问题。尽管如此,可以省略声明它们的析构函数,并允许编译器隐式生成它们。


用于包装纯虚拟函数的Boost.Python代码看起来不错。以下是一个基于原始代码的完整示例,演示了它的用法:

#include <boost/python.hpp>
// Mockup abstract type.
class polygon
{
protected:
 int width, height;
public:
  polygon(int a, int b): width(a), height(b) {}
  virtual int area () = 0;
  virtual ~polygon() = default;
};
// Wrapper to allow calling Python overrides.
struct polygon_wrap
  : polygon, boost::python::wrapper<polygon>
{
  polygon_wrap(): polygon(0, 0) {}
  int area() { return this->get_override("area")(); }
};
BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  // Expose models.
  python::class_<polygon_wrap, boost::noncopyable>(
      "Polygon", python::init<>())
    .def("area", python::pure_virtual(&polygon::area))
    ;
}

交互式使用:

>>> import example
>>> class BadPolygon(example.Polygon):
...    pass
...
>>> class Square(example.Polygon):
...     def __init__(self, length):
...         example.Polygon.__init__(self)
...         self.length = length
...     def area(self):
...         return self.length**2
...
>>> try:
...     polygon = BadPolygon()
...     assert(isinstance(polygon, example.Polygon))
...     got_runtime_error = False
...     polygon.area()
... except RuntimeError:
...     got_runtime_error = True
... finally:
...     assert(got_runtime_error)
...
>>> polygon = Square(6)
>>> assert(isinstance(polygon, example.Polygon))
>>> assert(36 == polygon.area())