简体   繁体   中英

Wrapping the pure virtual function using Boost::Python

I am now learning exposing c++ class to Python using Boost::Python , and I wrote the following code.

Compiling the code is all right. But when I import the code from Python side, it shows the following errors:

Traceback (most recent call last): File "test4.py", line 1, in

import shape;

ImportError: /home/ruofan/Boost/Class/shape.so: undefined symbol: _ZTI7Polygon

How can I solve the problem?

#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));
}

The problem is that non-pure virtual functions are being declared but never defined. This results in the library having undefined references to a class' typeinfo:

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

In this particular case, the destructors are never defined:

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

To resolve this, define the Polygyon destructor:

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

The same issue exists for Rectangle and Triangle types. Although, one could omit declaring their destructors and allow the compiler to implicitly generate them.


The Boost.Python code for wrapping the pure-virtual function looks fine. Here is a complete example based on the original code that demonstrates its usage:

#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))
    ;
}

Interactive usage:

>>> 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())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM