Python:源于C++;python中的对象:无法添加到C++;基类列表

Python:源于C++;python中的对象:无法添加到C++;基类列表,python,c++,boost,boost-python,Python,C++,Boost,Boost Python,我试图通过继承扩展Python中现有的C++对象。 我可以成功地做到这一点,并运行Python中重写的虚拟方法。然而,当我尝试将Python对象添加到C++基础对象类型的指针列表中时(Python类已经重写的基础对象),我会得到一个类型错误:“尝试追加一个无效类型”< /P> 我确信这个错误是因为没有从派生*到基*的“隐式转换”功能。在C++中,这将被定义为: 可以用python来定义它吗 我怎样才能做到这一点 下面是重现这种行为的示例代码 C++ 如果您有任何帮助或想法,我们将不胜感激。函数B

我试图通过继承扩展Python中现有的C++对象。 我可以成功地做到这一点,并运行Python中重写的虚拟方法。然而,当我尝试将Python对象添加到C++基础对象类型的指针列表中时(Python类已经重写的基础对象),我会得到一个类型错误:“尝试追加一个无效类型”< /P> 我确信这个错误是因为没有从派生*到基*的“隐式转换”功能。在C++中,这将被定义为: 可以用python来定义它吗

我怎样才能做到这一点

下面是重现这种行为的示例代码

C++

如果您有任何帮助或想法,我们将不胜感激。

函数
BaseList.append()
会收到正确类型的参数;然而,这个论点有一个不恰当的价值。在Python中,
派生的
初始值设定项没有初始化其层次结构的
sandbox.Base
部分。这将导致Booj.python对象不包含C++ <代码> BaseButh//Cord>对象。因此,当<>代码> Baselist.AppEnter()/Cuth>试图提取C++ <代码> BaseBase< /Cord>对象时,它失败并引发错误。

派生类(基):
定义初始化(自):
self.name=“测试”
#基址未初始化。
def f(自我):
打印(“你好!”
d=派生的()
d、 f()#`derived.f()`通过Python的方法解析顺序进行解析。
#它没有调用'BaseWrap::f()`。
a=a()
a、 追加(d)#d不包含BaseWrap对象,因此会抛出。
若要解决此问题,请在
派生中显式调用

派生类(基):
定义初始化(自):
self.name=“测试”
基本。初始(自我)
但是,尝试这样做会暴露出
BaseWrap
如何公开的其他问题:

  • sandbox.Base
    类必须可以从Python构造,因此绑定不能提供
    boost::Python::no_init
    作为其初始值设定项规范。通常,只想使用<代码> Boo::Python::NOTIIN < /COD>当C++对象从C++被显式实例化并传递到Python时,例如通过工厂函数。
  • T
    BaseWrap
    时,
    Base*
    HeldType
    不能满足
    HeldType
    的要求。特别是,
    HeldType
    需要是:
    BaseWrap
    ,一个派生自
    BaseWrap
    的类,或者是一个可取消引用的类型,
    boost::python::pointee::type
    BaseWrap
    或派生自
    BaseWrap
    的类。有关详细要求,请参见规范
可以通过如下方式公开类来解决这些问题:

namespace python=boost::python;
python::class_389;(“Base”,python::init())
.def(“f”,python::pure_virtual(&Base::f))
;

这里是一个完整的例子,它将一个从C++暴露类派生的对象传递给一个C++向量,它通过 Vector TyrBug

#include <vector>
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

struct base
{
  virtual ~base() {}
  virtual int perform() = 0;
};

struct base_wrap: base, boost::python::wrapper<base>
{
  int perform() { return int(this->get_override("perform")()) - 10; }
};

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<base_wrap, boost::noncopyable>("Base", python::init<>())
    .def("perform", python::pure_virtual(&base::perform))
    ;

  python::class_<std::vector<base*>>("BaseList")
    .def(python::vector_indexing_suite<std::vector<base*>>())
    ;

  python::def("do_perform", +[](base* object) {
    return object->perform();
  });
}
对于集合和指针,通常会有一些警告。在这种情况下:

  • 基本列表
    对象对其元素引用的对象没有共享所有权。请注意确保容器引用的对象的生存期至少与容器本身一样长。在上面的示例中,如果删除了对象
    d
    ,则调用
    base\u list[0].perform()
    可能会导致未定义的行为
  • 不能迭代
    base\u列表
    ,因为迭代器的值将尝试执行
    base*
    -到Python的转换,但该转换不存在

上面的示例还演示了函数调度的差异。如果Python可以直接调用一个方法,它将使用自己的方法解析机制来实现。请注意
base\u list[0]。perform()
示例。do\u perform(base\u list[0])
返回不同的值,因为一个值通过操纵结果的
base\u wrap::perform()
进行调度,而另一个值则不返回

在原始代码中:

派生类(sandbox.Base):
...
def f(自我):
打印(“你好!”
d=派生的()
d、 f()
由于Python知道
derived.f()
,调用
d.f()
将不会通过
BaseWrap::f()
进行调度。如果调用了
BaseWrap::f()
,它将被抛出,因为
derived.f()
返回了
None
,这将无法转换为
int

struct BaseWrap:Base,wrapper{
int f(){返回此->获取覆盖(“f”)();}
//^~~返回boost::python::object,falling到
//提取'int'将抛出。
};

感谢您的详细解释。我希望我能对答案投更多的赞成票。我正在努力解决“一个人不能在base_列表上迭代,因为迭代器的值将尝试执行base*-到Python的转换,而这是不存在的。”这一部分现在开始。但是其余的都很好。@user3035260当在
BaseList
对象上迭代时,Python不能安全地假定所有
base*
都是
base\u wrap
的实例。考虑C++类型<代码> FoO < /C> >源于 Base<代码>,并将指向<代码>指针的“Foo< /Calp>实例”推到:在Python对象中保存的:vector < /COD>。有关“代码> VECRTHORIZONG OWITY CONUS/CODE >的更多细节,请考虑阅读此代码。
class derived(Base):
    def __init__(self):
        self.name = "test"
    def f(self):
        print("Hello Derived!")

d = derived()
d.f()          # Output: Hello Derived!

a = A()
a.baseList.append(d) # TypeError: Attempting to append an invalid type
#include <vector>
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

struct base
{
  virtual ~base() {}
  virtual int perform() = 0;
};

struct base_wrap: base, boost::python::wrapper<base>
{
  int perform() { return int(this->get_override("perform")()) - 10; }
};

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<base_wrap, boost::noncopyable>("Base", python::init<>())
    .def("perform", python::pure_virtual(&base::perform))
    ;

  python::class_<std::vector<base*>>("BaseList")
    .def(python::vector_indexing_suite<std::vector<base*>>())
    ;

  python::def("do_perform", +[](base* object) {
    return object->perform();
  });
}