2015-04-06 159 views
0

我現在正在學習如何使用Boost::Python將C++類暴露給Python,並且我編寫了下面的代碼。使用Boost封裝純虛函數:: Python

編譯代碼是好的。但是,當我從導入的Python端的代碼,它顯示了以下錯誤:

回溯(最近通話最後一個): 文件 「test4.py」,1號線,在

import shape; 

導入錯誤:/ home/ruofan/Boost/Class/shape.so:undefined symbol:_ZTI7Polygon

我該如何解決這個問題?

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

回答

1

問題是,非純虛擬函數正在被聲明,但從來沒有定義。這導致在庫不必所屬類別一類的未定義的引用:

$ 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代碼看起來很好。這是在原有基礎上的代碼一個完整的例子,demonstrates其用法:

#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()) 
+0

太謝謝你了!是的,你是對的,這真的很有幫助! – 2015-04-09 19:19:42