<>抽象的C++类不能以这种方式暴露给Boost.Python。Python<a href="http://www.boost.org/doc/libs/1_55_0/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions" rel="noreferrer">tutorial</a>给出了如何公开纯虚拟函数的示例。简而言之,当用^ {CD1> }装饰方法时,需要创建包装类型,以允许C++对虚拟函数进行多态分解,而虚拟函数实现将委托在Python对象层次结构中解析函数。</p>
<pre class="lang-cpp prettyprint-override"><code>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))
;
</code></pre>
<p>有关详细信息,当通过<code>boost::python::class_</code>公开类型时,<code>HeldType</code>默认为公开的类型,并且<code>HeldType</code>在Python对象中构造。<a href="http://www.boost.org/doc/libs/1_55_0/libs/python/doc/v2/class.html#class_-spec" rel="noreferrer">^{<cd5>}</a>文档说明:</p>
<blockquote>
<p>Template Parameter:</p>
<ul>
<li><code>T</code>: The class being wrapped</li>
<li><code>HeldType</code>: Specifies the type that is actually embedded in a Python object wrapping a <code>T</code> instance [...]. Defaults to <code>T</code>.</li>
</ul>
</blockquote>
<p>因此,<code>boost::python::class_<Base></code>将失败,因为<code>T = Base</code>和<code>HeldType = Base</code>,以及Boost.Python将尝试将<code>HeldType</code>的对象实例化为表示<code>Base</code>实例的Python对象。这个实例化将失败,因为<code>Base</code>是一个抽象类。</p>
<hr/>
<p>下面是一个完整的示例,显示了<code>BaseWrap</code>类的使用。</p>
<pre class="lang-cpp prettyprint-override"><code>#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>());
}
</code></pre>
<p>以及它的用法:</p>
<pre class="lang-python prettyprint-override"><code>>>> 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
</code></pre>
<hr/>
<p>可以在Boost.Python中公开抽象类,方法是不使用默认的初始值设定项(<code>boost::python::no_init</code>)和不可复制(<code>boost::noncopyable</code>)。缺少初始值设定项会阻止Python类型从中派生,从而有效地防止重写。另外,^ {CD15}}在C++中实现的实现细节,由^ {CD16> }是无关紧要的。如果Python根本不应该知道<code>foo()</code>方法,那么省略通过<code>def()</code>公开它。</p>
<pre><code>#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>());
}
</code></pre>
<p>交互使用:</p>
<pre class="lang-python prettyprint-override"><code>>>> 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'
</code></pre>