簡體   English   中英

擴展通過Boost.Python公開的虛擬C ++類

[英]Extending a virtual C++ class exposed via Boost.Python

我正在嘗試使用Boost.Python公開此C ++類:

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 shell中將VAlgorithm的子級定義為python類。 此示例之后 ,我定義了一個回調類:

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 shell中。 然后,我嘗試定義一個子類,並調用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和擴展的新手)。 誰能幫幫我嗎? 謝謝

我想我找到了解決方案。 通過我在提問中引用的示例以及此處的boost文檔,我發現問題在於回調類是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'
>>>

我所做的事情與此非常相似。 您為什么不遵循評論中已經找到的內容?

當您在Python中創建派生於VAlgorithm的類的實例時,必須用C ++實例化VAlgorithm_callback來表示它。 如果沒有在BOOST_PYTHON_MODULE中聲明任何構造函數,則是不可能的。

按照示例中的方式進行操作應該可以:

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

定義子類的init時,可以使用以下語法調用父構造函數(但是您的代碼也可以工作,這就是我的方法)。 在您使用的示例中,它們甚至都沒有定義init,因此調用了父級init

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM