簡體   English   中英

Boost.python繼承自包裝類

[英]Boost.python inheriting from wrapped classes

我在使用boost.python為現有庫創建python綁定時遇到了問題。 方案如下:

#include<boost/python.hpp>

namespace bp = boost::python;

struct Base {
    std::stringstream _myString;
    Base() { };
    Base(const Base& base) { _myString<<base._myString.str(); }

    void getString(std::stringstream& some_string) {
        _myString.str("");
        _myString<<some_string.str();
        std::cout<<"Got string: \""<<_myString.str()<<"\""<<std::endl;
    }
};

struct BaseWrapper : Base,
                     bp::wrapper<Base>
{
    BaseWrapper() :
        Base(),
        bp::wrapper<Base>() { };

    BaseWrapper(const Base& base) :
        Base(base),
        bp::wrapper<Base>() { };

    void getString(bp::object pyObj) {
        std::string strLine = bp::extract<std::string>(pyObj);
        std::stringstream sstrLine;
        sstrLine<<strLine;
        Base::getString(sstrLine);
    }
};

struct Derived : Base
{
    Derived() : Base() { };
    Derived(const Derived& derived) : Base() { _myString<<derived._myString.str(); };
};

struct DerivedWrapper : Derived,
                        bp::wrapper<Derived>
{
    DerivedWrapper() :
        Derived(),
        bp::wrapper<Derived>() { };

    DerivedWrapper(const Derived derived) :
        Derived(derived),
        bp::wrapper<Derived>() { };
};

BOOST_PYTHON_MODULE(testInheritance){
    bp::class_<BaseWrapper>("Base")
        .def("getString", &BaseWrapper::getString);

    bp::class_<DerivedWrapper, bp::bases<Base> >("Derived");
}

(對不起長代碼塊,這是我能想到的最小例子。)

您可以看到我必須覆蓋BaseWrapper中的getString()方法,以便它可以使用Python字符串,這部分工作正常:

>>> import testInheritance
>>> base = testInheritance.Base()
>>> base.getString("bla")
Got string: "bla"
>>>

一旦我嘗試從Derived實例調用getString ,就會出現問題:

>>> derived = testInheritance.Derived()
>>> derived.getString("bla")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    Base.getString(Derived, str)
did not match C++ signature:
    getString(BaseWrapper {lvalue}, boost::python::api::object)
>>>

我可以理解這里出了什么問題,但我不知道如何解決這個問題。 我將不勝感激任何幫助!

最誠摯的問候,eDude

問題是, DerivedWrapperBaseWrapper沒有任何關系。 因此DerivedWrapper需要提供自己的python改編的void getString(bp::object pyObj)

因此,使其工作的一種方法是這樣的:

struct DerivedWrapper : Derived,
                        bp::wrapper<Derived>
{
    DerivedWrapper() :
        Derived(),
        bp::wrapper<Derived>() { };

    DerivedWrapper(const Derived derived) :
        Derived(derived),
        bp::wrapper<Derived>() { };

    void getString(bp::object pyObj) {
        std::string strLine = bp::extract<std::string>(pyObj);
        std::stringstream sstrLine;
        sstrLine<<"(from DerivedWrapper) "<<strLine;
        Derived::getString(sstrLine);
    }
};

[...]

    bp::class_<DerivedWrapper, bp::bases<Base> >("Derived")
        .def("getString", &DerivedWrapper::getString);

和輸出

base = testInheritance.Base()
base.getString("bla")

derived = testInheritance.Derived()
derived.getString("blub")

如預期的那樣

Got string: "bla"
Got string: "(from DerivedWrapper) blub"

我遇到了與我設法解決的問題完全相同的問題,但在某些特殊情況下,解決方案存在一些內部錯誤。 當需要從boost :: python傳遞的值創建boost :: weak_ptr引用時,在python中使用boost :: shared_ptr存在一個已知問題。 我不會詳細介紹與帖子無關的細節。 無論如何,我需要將boost :: shared_ptr包裝到另一個類(我稱之為PythonSharedPtr)來隱藏boost :: python中的boost :: shared_ptr然后我得到類似的問題。 考慮以下設置:類A在c ++端用作boost :: shared_ptr,類B(從A繼承)用作boost :: shared_ptr,在python中,shared_ptr被包裝到另一個類中(為了進一步說明為什么我需要創建它,解釋如下: boost :: python和weak_ptr:東西消失 http://mail.python.org/pipermail/cplusplus-sig/2009-November/014983.html

那么我需要編寫適當的導出到boost python:class_,wrapped_shared_ptr,noncopyable>和class_,wrapped_shared_ptr,noncopyable>

我想到現在它與你的代碼相似。 棘手的部分是如何允許在boost :: python中使用base來導出B(而shared_ptr與shared_ptr無關)。 經過對boost :: python源代碼的一些研究,並提供了相當不錯的解決方案,但它僅適用於案例,B類沒有多重繼承。

這是代碼:

namespace boost { namespace python { namespace objects
{
    template<typename Source, typename Target>
    struct shared_ptr_cast_generator
    {
        static void* execute(void* source)
        {
            const boost::shared_ptr<Source>* sourcePtr = static_cast<boost::shared_ptr<Source>*>(source);
            const boost::shared_ptr<Target> target     = boost::dynamic_pointer_cast<Target>(*sourcePtr);
            if(reinterpret_cast<size_t>(target.get()) == reinterpret_cast<size_t>(sourcePtr->get()))
                return source;
            else
            {
                // assertion which is triggered when multi-inheritance is used for Source type
                // in this case it is necessary to create new instance of shared_ptr<Target> but
                // it is not possible to make it in-place due to memory leak
                assert(!"Wrong cast");
                return nullptr;
            }
        }
    };

    template<typename Source, typename Target>
    struct cast_generator<boost::shared_ptr<Source>, boost::shared_ptr<Target> >
    {
        typedef shared_ptr_cast_generator<Source, Target> type;
    };
}}}

通過提供這樣的代碼,可以調整第二次導出到python:class_,wrapped_shared_ptr,noncopyable,bases>

只需要小心執行函數中存儲的轉換 - 如果Source和Target之間存在轉換,它將返回相同的地址 - 因此如果只是將Source *重新解釋為Target *,它必須也是有效的(兩個類中的數據必須完全相同)地方)。

也許這種解決方案在你的情況下是不夠的,但至少它可以給你一些想法。

暫無
暫無

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

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