2012-09-06 16 views
1

暴露我試圖揭露使用Boost.Python的這個C++類:延伸的虛擬C++類通過Boost.Python的

class VAlgorithm { 
public: 

    VAlgorithm(const char *name); 

    virtual ~VAlgorithm(); 

    virtual bool Initialize() = 0; 
    virtual bool Process() = 0; 
    virtual bool Finalize() = 0; 

    virtual const char *GetName() const; // Default implementation in cpp file 
} 

我的最終目標是在Python殼爲Python類來定義VAlgorithm的孩子。繼this example,我定義了一個回調類:

class VAlgorithm_callback: public VAlgorithm { 
public: 
    VAlgorithm_callback(PyObject *p, const char *name) : 
     self(p), VAlgorithm(name) { 
    } 
    const char * GetName() const { 
    return call_method<const char *>(self, "GetName"); 
    } 

    static const char * GetName_default(const VAlgorithm& self_) { 
    return self_.VAlgorithm::GetName(); 
    } 

private: 
    PyObject *self; 
}; 

現在我只露出類本身和getName()方法。由於它是一個虛擬的類,我把這個代碼內BOOST_PYTHON_MODULE:

class_<VAlgorithm, VAlgorithm_callback, boost::noncopyable>("VAlgorithm", no_init) // 
    .def("GetName", &VAlgorithm_callback::GetName_default); // 

我可以編譯此和在Python殼加載模塊。然後我嘗試定義一個子類,並呼籲在C++代碼中定義的的GetName()默認實現:

>>> class ConcAlg1(VAlgorithm): 
... pass 
... 
>>> c1 = ConcAlg1("c1") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
RuntimeError: This class cannot be instantiated from Python 
>>> class ConcAlg2(VAlgorithm): 
... def __init__(self, name): 
...  pass 
... 
>>> c2 = ConcAlg2("c2") 
>>> c2.GetName() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
Boost.Python.ArgumentError: Python argument types in 
    VAlgorithm.GetName(ConcAlg2) 
did not match C++ signature: 
    GetName(VAlgorithm) 
>>> class ConcAlg3(VAlgorithm): 
... def __init__(self, name): 
...  super(ConcAlg3, self).__init__(self, name) 
... 
>>> c3 = ConcAlg3("c3") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in __init__ 
RuntimeError: This class cannot be instantiated from Python 

我不是(只是面臨這些問題的第一次)的專家,但在我看來, ConcAlg1和ConcAlg3嘗試實例化一個VAlgorithm對象,並且因暴露VAlgorithm時使用no_init參數而失敗(我不能忽略它或者代碼不會編譯),而ConcAlg2不能調用GetName(),因爲它以某種方式不被認爲是VAlgorithm的一個孩子。 我一定在做一些細小的錯誤,但我無法弄清楚什麼(我是Boost.Python和擴展的新手)。誰能幫幫我嗎?謝謝

回答

0

我已經做了非常相似的事情。你爲什麼不按照你在評論中已經發現的內容?

當您創建一個派生於Python中的VAlgorithm的類的實例時,VAlgorithm_callback將不得不在C++中實例化以表示它。如果你沒有在BOOST_PYTHON_MODULE中聲明任何構造函數是不可能的。

儘自己的例子一樣,應該確定方式:

class_<VAlgorithm, VAlgorithm_callback, boost::noncopyable>("VAlgorithm", init<std::string>()) 

當你定義子類的初始化,你可以用下面的語法來調用父類的構造函數(但你的代碼可能工作也是如此,這就是我的方式)。在你使用的例子中,他們甚至沒有定義init,所以調用父代。

class ConcAlg3(VAlgorithm): 
    def __init__(self, name): 
    VAlgorithm.__init__(self, name) 
+0

事實上,我在找到錯誤後寫了我的答案。我認爲我被一個記錄不完整的例子和我對Boost.Python的糟糕知識誤導了。謝謝你的幫助! –

0

我想我找到了解決方案。通過我在我的問題上引用的例子以及boost文檔here,我發現問題在於回調類是Boost.Python包裝的真正的類,並且它必須是具體的類。所以,我在它執行的缺失純虛方法:

class VAlgorithm_callback: public VAlgorithm { 
public: 
    VAlgorithm_callback(PyObject *p, const char *name) : 
     self(p), VAlgorithm(name) { 
    } 

    virtual bool Initialize() { 
    return call_method<bool>(self, "Initialize"); 
    } 
    virtual bool Process() { 
    return call_method<bool>(self, "Process"); 
    } 
    virtual bool Finalize() { 
    return call_method<bool>(self, "Finalize"); 
    } 

    const char * GetName() const { 
    return call_method<const char *>(self, "GetName"); 
    } 

// Supplies the default implementation of GetName 
    static const char * GetName_default(const VAlgorithm& self_) { 
    return self_.VAlgorithm::GetName(); 
    } 

private: 
    PyObject *self; 
}; 

,也修改了包裝爲:

class_<VAlgorithm, boost::shared_ptr<VAlgorithm_callback>, boost::noncopyable ("VAlgorithm", init<const char *>()) // 
.def("Initialize", &VAlgorithm_callback::Initialize) 
.def("Process", &VAlgorithm_callback::Process) 
.def("Finalize", &VAlgorithm_callback::Finalize) 
.def("GetName", &VAlgorithm_callback::GetName_default); 

現在我可以在Python中定義一個子類,並調用默認的getName()方法:

>>> class ConcAlg(VAlgorithm): 
... pass 
... 
>>> c = ConcAlg("c") 
>>> c.GetName() 
'c' 
>>>