在Boost Python中公开C ++接口 [英] Exposing C++ interface in boost python

查看:84
本文介绍了在Boost Python中公开C ++接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

示例代码说明:

struct Base
{
  virtual int foo() = 0;
};

struct Derived : public Base
{
  virtual int foo()
  {
    return 42;
  }
};

Base* get_base()
{
  return new Derived;
}

BOOST_PYTHON_MODULE(libTestMod)
{
  py::class_<Base>("Base", py::no_init)
    .def("foo", py::pure_virtual(&Base::foo));

  py::def("get_base", get_base, py::return_internal_reference<>()); //ignore mem leak
}

  • Base :: foo在python中不会被覆盖
  • Base:foo将用c ++实现,但不应公开给python
  • 尝试了以上代码,但无法编译.

    Tried the above code but fails to compile.

    更新: 编译错误:

    /path/to/boostlib/boost/1.53.0-0/common/include/boost/python/object/value_holder.hpp:66:11: error: cannot declare field 'boost_1_53_0::python::objects::value_holder<Base>::m_held' to be of abstract type 'Base'
    Main.C:59:8: note:   because the following virtual functions are pure within 'Base':
    Main.C:61:15: note:         virtual int Base::foo()
    

    推荐答案

    抽象C ++类无法以这种方式暴露给Boost.Python. Boost.Python

    Abstract C++ classes cannot be exposed in this manner to Boost.Python. The Boost.Python tutorial gives examples as to how to expose pure virtual functions. In short, when decorating methods with boost::python::pure_virtual, a wrapper type needs to be created to allow C++ to polymorphic resolve the virtual function, and the virtual function implementation will delegate resolving the function polymorphically in the Python object's hierarchy.

    struct BaseWrap : Base, boost::python::wrapper<Base>
    {
      int foo()
      {
        return this->get_override("foo")();
      }
    };
    
    ...
    
    boost::python::class_<BaseWrap>("Base", ...)
      .def("foo", boost::python::pure_virtual(&Base::foo))
      ;
    

    有关详细信息,当通过boost::python::class_公开类型时,HeldType默认为公开的类型,并且HeldType是在Python对象中构造的. class_ 文档状态:

    For details, when a type is exposed via boost::python::class_, HeldType defaults to the type being exposed, and the HeldType is constructed within a Python object. The class_ documentation states:

    模板参数:

    • T:正在包装的类
    • HeldType:指定包装在T实例[...]中的Python对象中实际嵌入的类型.默认为T.
    • T: The class being wrapped
    • HeldType: Specifies the type that is actually embedded in a Python object wrapping a T instance [...]. Defaults to T.

    因此,boost::python::class_<Base>将失败,因为T = BaseHeldType = Base,以及Boost.Python将尝试将HeldType的对象实例化为表示Base实例的Python对象.此实例化将失败,因为Base是抽象类.

    Hence, the boost::python::class_<Base> will fail, because T = Base and HeldType = Base, and Boost.Python will try to instantiate an object of HeldType into a Python object that represents an instance of Base. This instantiation will fail as Base is an abstract class.

    这是一个完整的示例,显示了BaseWrap类的使用.

    Here is a complete example showing the use of a BaseWrap class.

    #include <boost/python.hpp>
    
    struct Base
    {
      virtual int foo() = 0;
      virtual ~Base() {}
    };
    
    struct Derived : public Base
    {
      virtual int foo()
      {
        return 42;
      }
    };
    
    Base* get_base()
    {
      return new Derived;
    }
    
    namespace python = boost::python;
    
    /// @brief Wrapper that will provide a non-abstract type for Base.
    struct BaseWrap : Base, python::wrapper<Base>
    {
      BaseWrap() {}
    
      BaseWrap(const Base& rhs)
        : Base(rhs)
      {}
    
      int foo()
      {
        return this->get_override("foo")();
      }
    };
    
    BOOST_PYTHON_MODULE(example)
    {
      python::class_<BaseWrap>("Base")
        .def("foo", python::pure_virtual(&Base::foo));
        ;
    
      python::def("get_base", &get_base,
                  python::return_value_policy<python::manage_new_object>());
    }
    

    及其用法:

    >>> import example
    >>> class Spam(example.Base):
    ...     pass
    ... 
    >>> Spam().foo()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    RuntimeError: Pure virtual function called
    >>> class Egg(example.Base):
    ...     def foo(self):
    ...         return 100
    ... 
    >>> e = Egg()
    >>> e.foo()
    100
    >>> d = example.get_base()
    >>> d.foo()
    42
    


    可以通过在没有默认初始化器(boost::python::no_init)和不可复制(boost::noncopyable)的情况下公开Boost.Python中的抽象类.缺少初始化器会阻止从其派生Python类型,从而有效地防止覆盖.此外,由Derived在C ++中实现Base::foo()的实现细节是无关紧要的.如果Python根本不了解foo()方法,请省略通过def()公开它.


    It is possible to expose an abstract class in Boost.Python by exposing it with no default initializer (boost::python::no_init) and non-copyable (boost::noncopyable). The lack of an initializer prevents Python types from deriving from it effectively preventing overriding. Additionally, the implementation detail that Base::foo() is implemented within C++ by Derived is inconsequential. If Python should not know about a foo() method at all, then omit exposing it via def().

    #include <boost/python.hpp>
    
    struct Base
    {
      virtual int foo() = 0;
      virtual ~Base() {}
    };
    
    struct Derived
      : public Base
    {
      virtual int foo()
      {
        return 42;
      }
    };
    
    struct OtherDerived
      : public Base
    {
      virtual int foo()
      {
        return 24;
      }
    };
    
    Base* get_base()
    {
      return new Derived;
    }
    
    Base* get_other_base()
    {
      return new OtherDerived;
    }
    
    BOOST_PYTHON_MODULE(example)
    {
      namespace python = boost::python;
      python::class_<Base, boost::noncopyable>("Base", python::no_init)
        ;
    
      python::class_<Derived, python::bases<Base> >("Derived", python::no_init)
        .def("foo", &Base::foo)
        ;
    
      python::class_<OtherDerived, python::bases<Base> >(
          "OtherDerived", python::no_init)
        ;
    
      python::def("get_base", &get_base,
                  python::return_value_policy<python::manage_new_object>());
    
      python::def("get_other_base", &get_other_base,
                  python::return_value_policy<python::manage_new_object>());
    }
    

    互动用法:

    >>> import example
    >>> b = example.get_base()
    >>> b.foo()
    42
    >>> b = example.get_other_base()
    >>> b.foo()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'OtherDerived' object has no attribute 'foo'
    

    这篇关于在Boost Python中公开C ++接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆