从包装类继承的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
问题是,DerivedWrapper
与BaseWrapper
没有关系。因此,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_pt,然后我遇到了类似的问题。请考虑以下设置:类A在c++端被用作boost::shared_ptr,类B(从A继承)被用作boost::shared_pt,在python中,两个shared_ptr都被封装到另一个类中(有关我为什么需要制作它的更多信息,请参阅:boost::python和weak_ptr:东西正在消失http://mail.python.org/pipermail/cplusplus-sig/2009-November/014983.html
因此,我需要编写适当的导出到boost python:class_,wrapped_shared_ptr,不可复制>和class_,wrapped_shared_ptr,不可复制>
我认为到目前为止,它与您的代码相似。棘手的部分是如何允许在boost::python中使用基来导出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,不可复制,base>
只要小心存储在execute函数中的转换-如果Source和Target之间存在转换,它会返回相同的地址-所以如果您只是将Source*重新解释为Target*,它也必须有效(两个类中的数据必须存储在完全相同的位置)。
也许这样的解决方案在你的情况下是不够的,但至少它可以给你一些想法。
- 我应该包含什么来制作 boost.python 扩展?
- C++ 和 Boost.Python - 如何将变量公开给 python 并在循环中更新它?
- 如何将来自 Boost.Python 的map_indexing_suite与自定义而不是标准对象一起使用?
- Boost Python Numpy - 要初始化的未定义引用
- Boost.Python :C++模板类型匹配的嵌套命名空间
- Boost.Python 列出了所有公开的类和属性
- Boost.Python 在静态库方面失败
- 在cpp中使用boost-python的python代码是否进行动态内存分配
- Boost.Python 和导入 dll,"The specified module could not be found"
- 无法将__str__特殊方法与Boost::Python接口
- 编译时出现Boost.python链接错误
- 使用 Boost/Python 的未定义符号 - 复杂
- Boost.Python 和C++导入到 Python 3 时编译库错误
- 两个并发的 Python 进程可以在 Boost Python 中运行吗?
- 通过 Boost Python 将 Python 函数转换为 C++,用作回调
- 编译在 Python 代码内部调用的 C++ 代码时出错,使用 Boost Python
- Boost.Python.ArgumentError: World.set(World, str) 中的 Python
- 使用 boost python 从 c++ 为 python 中的类成员变量赋值
- Boost Python 不断链接 Python27 库
- 使用 python3 为 msvc 构建 boost python - 链接器错误