mirror of
https://github.com/boostorg/python.git
synced 2026-01-25 06:22:15 +00:00
New Wrapper Facility
[SVN r26207]
This commit is contained in:
@@ -31,7 +31,6 @@
|
||||
<dt><span class="section"><a href="exposing.html#python.class_properties">Class Properties</a></span></dt>
|
||||
<dt><span class="section"><a href="exposing.html#python.inheritance">Inheritance</a></span></dt>
|
||||
<dt><span class="section"><a href="exposing.html#python.class_virtual_functions">Class Virtual Functions</a></span></dt>
|
||||
<dt><span class="section"><a href="exposing.html#python.deriving_a_python_class">Deriving a Python Class</a></span></dt>
|
||||
<dt><span class="section"><a href="exposing.html#python.virtual_functions_with_default_implementations">Virtual Functions with Default Implementations</a></span></dt>
|
||||
<dt><span class="section"><a href="exposing.html#python.class_operators_special_functions">Class Operators/Special Functions</a></span></dt>
|
||||
</dl></div>
|
||||
@@ -226,10 +225,13 @@ Now we can inform Boost.Python of the inheritance relationship between
|
||||
Doing so, we get some things for free:</p>
|
||||
<div class="orderedlist"><ol type="1">
|
||||
<li>
|
||||
Derived automatically inherits all of Base's Python methods (wrapped C++ member functions)
|
||||
Derived automatically inherits all of Base's Python methods
|
||||
(wrapped C++ member functions)
|
||||
</li>
|
||||
<li>
|
||||
<span class="bold"><b>If</b></span> Base is polymorphic, <tt class="literal">Derived</tt> objects which have been passed to Python via a pointer or reference to <tt class="literal">Base</tt> can be passed where a pointer or reference to <tt class="literal">Derived</tt> is expected.
|
||||
<span class="bold"><b>If</b></span> Base is polymorphic, <tt class="literal">Derived</tt> objects which have been passed to
|
||||
Python via a pointer or reference to <tt class="literal">Base</tt> can be passed where a pointer
|
||||
or reference to <tt class="literal">Derived</tt> is expected.
|
||||
</li>
|
||||
</ol></div>
|
||||
<p>
|
||||
@@ -252,41 +254,55 @@ Boost.Python <a href="functions.html#python.call_policies" title="Call Policies"
|
||||
<div class="titlepage"><div><div><h3 class="title">
|
||||
<a name="python.class_virtual_functions"></a>Class Virtual Functions</h3></div></div></div>
|
||||
<p>
|
||||
In this section, we shall learn how to make functions behave
|
||||
polymorphically through virtual functions. Continuing our example, let us
|
||||
add a virtual function to our <tt class="literal">Base</tt> class:</p>
|
||||
In this section, we shall learn how to make functions behave polymorphically
|
||||
through virtual functions. Continuing our example, let us add a virtual function
|
||||
to our <tt class="literal">Base</tt> class:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Base</span><span class="special">
|
||||
{</span><span class="keyword">
|
||||
virtual</span><span class="special"> ~</span><span class="identifier">Base</span><span class="special">()</span><span class="special"> {}</span><span class="keyword">
|
||||
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> =</span><span class="number"> 0</span><span class="special">;</span><span class="special">
|
||||
};</span></tt></pre>
|
||||
<p>
|
||||
Since <tt class="literal">f</tt> is a pure virtual function, <tt class="literal">Base</tt> is now an abstract
|
||||
class. Given an instance of our class, the free function <tt class="literal">call_f</tt>
|
||||
calls some implementation of this virtual function in a concrete
|
||||
derived class:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="keyword">int</span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">Base</span><span class="special">&</span><span class="identifier"> b</span><span class="special">)</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> b</span><span class="special">.</span><span class="identifier">f</span><span class="special">();</span><span class="special"> }</span></tt></pre>
|
||||
<p>
|
||||
To allow this function to be implemented in a Python derived class, we
|
||||
need to create a class wrapper:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">
|
||||
{</span><span class="identifier">
|
||||
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">)</span><span class="special">
|
||||
:</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="keyword">
|
||||
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> call_method</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="identifier">self</span><span class="special">,</span><span class="string"> "f"</span><span class="special">);</span><span class="special"> }</span><span class="identifier">
|
||||
PyObject</span><span class="special">*</span><span class="identifier"> self</span><span class="special">;</span><span class="special">
|
||||
};</span><span class="keyword">
|
||||
|
||||
|
||||
struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">
|
||||
{</span><span class="identifier">
|
||||
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">)</span><span class="special">
|
||||
:</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="identifier">
|
||||
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">,</span><span class="identifier"> Base</span><span class="keyword"> const</span><span class="special">&</span><span class="identifier"> copy</span><span class="special">)</span><span class="special">
|
||||
:</span><span class="identifier"> Base</span><span class="special">(</span><span class="identifier">copy</span><span class="special">),</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="keyword">
|
||||
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> call_method</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="identifier">self</span><span class="special">,</span><span class="string"> "f"</span><span class="special">);</span><span class="special"> }</span><span class="keyword">
|
||||
int</span><span class="identifier"> default_f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span><span class="special"> }</span><span class="comment"> // <<=== ***ADDED***
|
||||
</span><span class="identifier"> PyObject</span><span class="special">*</span><span class="identifier"> self</span><span class="special">;</span><span class="special">
|
||||
One of the goals of Boost.Python is to be minimally intrusive on an existing C++
|
||||
design. In principle, it should be possible to expose the interface for a 3rd
|
||||
party library without changing it. It is not ideal to add anything to our class
|
||||
<tt class="computeroutput"><span class="identifier">Base</span></tt>. Yet, when you have a virtual function that's going to be overridden in
|
||||
Python and called polymorphically <span class="bold"><b>from C++</b></span>, we'll need to add some
|
||||
scaffoldings to make things work properly. What we'll do is write a class
|
||||
wrapper that derives from <tt class="computeroutput"><span class="identifier">Base</span></tt> that will unintrusively hook into the virtual
|
||||
functions so that a Python override may be called:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">,</span><span class="identifier"> wrapper</span><span class="special"><</span><span class="identifier">Base</span><span class="special">></span><span class="special">
|
||||
{</span><span class="keyword">
|
||||
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special">
|
||||
{</span><span class="keyword">
|
||||
return</span><span class="keyword"> this</span><span class="special">-></span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">)();</span><span class="special">
|
||||
}</span><span class="special">
|
||||
};</span></tt></pre>
|
||||
<p>
|
||||
Notice too that in addition to inheriting from <tt class="computeroutput"><span class="identifier">Base</span></tt>, we also multiply-
|
||||
inherited <tt class="computeroutput"><span class="identifier">wrapper</span><span class="special"><</span><span class="identifier">Base</span><span class="special">></span></tt> (See <a href="../../../../v2//wrapper.html" target="_top">Wrapper</a>). The
|
||||
<tt class="computeroutput"><span class="identifier">wrapper</span></tt> template makes the job of wrapping classes that are meant to
|
||||
overridden in Python, easier.</p>
|
||||
<div class="informaltable"><table class="table">
|
||||
<colgroup><col></colgroup>
|
||||
<tbody><tr><td>
|
||||
<span class="inlinemediaobject"><img src="../images/alert.png"></span> MSVC6/7 Workaround<p></p>
|
||||
<p></p>
|
||||
|
||||
If you are using Microsoft Visual C++ 6 or 7, you have to write <tt class="computeroutput"><span class="identifier">f</span></tt> as:<p></p>
|
||||
<p></p>
|
||||
<tt class="computeroutput"><span class="keyword">return</span><span class="identifier"> call</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="keyword">this</span><span class="special">-></span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">).</span><span class="identifier">ptr</span><span class="special">());</span></tt>.</td></tr></tbody>
|
||||
</table></div>
|
||||
<p>
|
||||
BaseWrap's overridden virtual member function <tt class="computeroutput"><span class="identifier">f</span></tt> in effect calls the
|
||||
corresponding method of the Python object through <tt class="computeroutput"><span class="identifier">get_override</span></tt>.</p>
|
||||
<p>
|
||||
Finally, exposing <tt class="computeroutput"><span class="identifier">Base</span></tt>:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">>(</span><span class="string">"Base"</span><span class="special">)</span><span class="special">
|
||||
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> pure_virtual</span><span class="special">(&</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">))</span><span class="special">
|
||||
;</span></tt></pre>
|
||||
<p><tt class="computeroutput"><span class="identifier">pure_virtual</span></tt> signals Boost.Python that the function <tt class="computeroutput"><span class="identifier">f</span></tt> is a pure virtual
|
||||
function.</p>
|
||||
<div class="informaltable"><table class="table">
|
||||
<colgroup><col></colgroup>
|
||||
<tbody><tr><td>
|
||||
@@ -297,120 +313,19 @@ many object oriented languages uses the term <span class="bold"><b>methods</b></
|
||||
correspond roughly to C++'s <span class="bold"><b>member functions</b></span>
|
||||
</td></tr></tbody>
|
||||
</table></div>
|
||||
<p>
|
||||
Our class wrapper <tt class="literal">BaseWrap</tt> is derived from <tt class="literal">Base</tt>. Its overridden
|
||||
virtual member function <tt class="literal">f</tt> in effect calls the corresponding method
|
||||
of the Python object <tt class="literal">self</tt>, which is a pointer back to the Python
|
||||
<tt class="literal">Base</tt> object holding our <tt class="literal">BaseWrap</tt> instance.</p>
|
||||
<div class="informaltable"><table class="table">
|
||||
<colgroup><col></colgroup>
|
||||
<tbody><tr><td>
|
||||
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>Why do we need BaseWrap?</b></span><p></p>
|
||||
<p></p>
|
||||
</td></tr></tbody>
|
||||
</table></div>
|
||||
<p><span class="emphasis"><em>You may ask</em></span>, "Why do we need the <tt class="literal">BaseWrap</tt> derived class? This could
|
||||
have been designed so that everything gets done right inside of
|
||||
Base."</p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p>
|
||||
One of the goals of Boost.Python is to be minimally intrusive on an
|
||||
existing C++ design. In principle, it should be possible to expose the
|
||||
interface for a 3rd party library without changing it. To unintrusively
|
||||
hook into the virtual functions so that a Python override may be called, we
|
||||
must use a derived class.</p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p>
|
||||
Note however that you don't need to do this to get methods overridden
|
||||
in Python to behave virtually when called <span class="emphasis"><em>from</em></span><span class="bold"><b>Python</b></span>. The only
|
||||
time you need to do the <tt class="literal">BaseWrap</tt> dance is when you have a virtual
|
||||
function that's going to be overridden in Python and called
|
||||
polymorphically <span class="emphasis"><em>from</em></span><span class="bold"><b>C++</b></span>.]</p>
|
||||
<p>
|
||||
Wrapping <tt class="literal">Base</tt> and the free function <tt class="literal">call_f</tt>:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Base</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">>(</span><span class="string">"Base"</span><span class="special">,</span><span class="identifier"> no_init</span><span class="special">)</span><span class="special">
|
||||
;</span><span class="identifier">
|
||||
def</span><span class="special">(</span><span class="string">"call_f"</span><span class="special">,</span><span class="identifier"> call_f</span><span class="special">);</span></tt></pre>
|
||||
<p>
|
||||
Notice that we parameterized the <tt class="literal">class_</tt> template with <tt class="literal">BaseWrap</tt> as the
|
||||
second parameter. What is <tt class="literal">noncopyable</tt>? Without it, the library will try
|
||||
to create code for converting Base return values of wrapped functions to
|
||||
Python. To do that, it needs Base's copy constructor... which isn't
|
||||
available, since Base is an abstract class.</p>
|
||||
<p>
|
||||
In Python, let us try to instantiate our <tt class="literal">Base</tt> class:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="special">>>></span><span class="identifier"> base</span><span class="special"> =</span><span class="identifier"> Base</span><span class="special">()</span><span class="identifier">
|
||||
RuntimeError</span><span class="special">:</span><span class="identifier"> This</span><span class="keyword"> class</span><span class="identifier"> cannot</span><span class="identifier"> be</span><span class="identifier"> instantiated</span><span class="identifier"> from</span><span class="identifier"> Python</span></tt></pre>
|
||||
<p>
|
||||
Why is it an error? <tt class="literal">Base</tt> is an abstract class. As such it is advisable
|
||||
to define the Python wrapper with <tt class="literal">no_init</tt> as we have done above. Doing
|
||||
so will disallow abstract base classes such as <tt class="literal">Base</tt> to be instantiated.</p>
|
||||
</div>
|
||||
<div class="section" lang="en">
|
||||
<div class="titlepage"><div><div><h3 class="title">
|
||||
<a name="python.deriving_a_python_class"></a>Deriving a Python Class</h3></div></div></div>
|
||||
<p>
|
||||
Continuing, we can derive from our base class Base in Python and override
|
||||
the virtual function in Python. Before we can do that, we have to set up
|
||||
our <tt class="literal">class_</tt> wrapper as:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Base</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">>(</span><span class="string">"Base"</span><span class="special">)</span><span class="special">
|
||||
;</span></tt></pre>
|
||||
<p>
|
||||
Otherwise, we have to suppress the Base class' <tt class="literal">no_init</tt> by adding an
|
||||
<tt class="literal"><span class="underline">_init</span>_()</tt> method to all our derived classes. <tt class="literal">no_init</tt> actually adds
|
||||
an <tt class="literal"><span class="underline">_init</span>_</tt> method that raises a Python RuntimeError exception.</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="special">>>></span><span class="keyword"> class</span><span class="identifier"> Derived</span><span class="special">(</span><span class="identifier">Base</span><span class="special">):</span><span class="special">
|
||||
...</span><span class="identifier"> def</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="special">
|
||||
...</span><span class="keyword"> return</span><span class="number"> 42</span><span class="special">
|
||||
...</span></tt></pre>
|
||||
<p>
|
||||
Cool eh? A Python class deriving from a C++ class!</p>
|
||||
<p>
|
||||
Let's now make an instance of our Python class <tt class="literal">Derived</tt>:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="special">>>></span><span class="identifier"> derived</span><span class="special"> =</span><span class="identifier"> Derived</span><span class="special">()</span></tt></pre>
|
||||
<p>
|
||||
Calling <tt class="literal">derived.f()</tt>:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="special">>>></span><span class="identifier"> derived</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span><span class="number">
|
||||
42</span></tt></pre>
|
||||
<p>
|
||||
Will yield the expected result. Finally, calling calling the free function
|
||||
<tt class="literal">call_f</tt> with <tt class="literal">derived</tt> as argument:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="special">>>></span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">derived</span><span class="special">)</span><span class="number">
|
||||
42</span></tt></pre>
|
||||
<p>
|
||||
Will also yield the expected result.</p>
|
||||
<p>
|
||||
Here's what's happening:</p>
|
||||
<div class="orderedlist"><ol type="1">
|
||||
<li>
|
||||
<tt class="literal">call_f(derived)</tt> is called in Python
|
||||
</li>
|
||||
<li>
|
||||
This corresponds to <tt class="literal">def("call_f", call_f);</tt>. Boost.Python dispatches this call.
|
||||
</li>
|
||||
<li>
|
||||
<tt class="literal">int call_f(Base& b) { return b.f(); }</tt> accepts the call.
|
||||
</li>
|
||||
<li>
|
||||
The overridden virtual function <tt class="literal">f</tt> of <tt class="literal">BaseWrap</tt> is called.
|
||||
</li>
|
||||
<li>
|
||||
<tt class="literal">call_method<int>(self, "f");</tt> dispatches the call back to Python.
|
||||
</li>
|
||||
<li>
|
||||
<tt class="literal">def f(self): return 42</tt> is finally called.
|
||||
</li>
|
||||
</ol></div>
|
||||
</div>
|
||||
<div class="section" lang="en">
|
||||
<div class="titlepage"><div><div><h3 class="title">
|
||||
<a name="python.virtual_functions_with_default_implementations"></a>Virtual Functions with Default Implementations</h3></div></div></div>
|
||||
<p>
|
||||
Recall that in the <a href="exposing.html#python.class_virtual_functions" title="Class Virtual Functions">previous section</a>, we
|
||||
wrapped a class with a pure virtual function that we then implemented in
|
||||
C++ or Python classes derived from it. Our base class:</p>
|
||||
We've seen in the previous section how classes with pure virtual functions are
|
||||
wrapped using Boost.Python's <a href="../../../../v2//wrapper.html" target="_top">class wrapper</a>
|
||||
facilities. If we wish to wrap <span class="bold"><b>non</b></span>-pure-virtual functions instead, the
|
||||
mechanism is a bit different.</p>
|
||||
<p>
|
||||
Recall that in the <a href="exposing.html#python.class_virtual_functions" title="Class Virtual Functions">previous section</a>, we
|
||||
wrapped a class with a pure virtual function that we then implemented in C++, or
|
||||
Python classes derived from it. Our base class:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Base</span><span class="special">
|
||||
{</span><span class="keyword">
|
||||
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> =</span><span class="number"> 0</span><span class="special">;</span><span class="special">
|
||||
@@ -420,31 +335,46 @@ had a pure virtual function <tt class="literal">f</tt>. If, however, its member
|
||||
not declared as pure virtual:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Base</span><span class="special">
|
||||
{</span><span class="keyword">
|
||||
virtual</span><span class="special"> ~</span><span class="identifier">Base</span><span class="special">()</span><span class="special"> {}</span><span class="keyword">
|
||||
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="number"> 0</span><span class="special">;</span><span class="special"> }</span><span class="special">
|
||||
};</span></tt></pre>
|
||||
<p>
|
||||
and instead had a default implementation that returns <tt class="literal">0</tt>, as shown above,
|
||||
we need to add a forwarding function that calls the <tt class="literal">Base</tt> default virtual
|
||||
function <tt class="literal">f</tt> implementation:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">
|
||||
{</span><span class="identifier">
|
||||
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">)</span><span class="special">
|
||||
:</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="keyword">
|
||||
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> call_method</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="identifier">self</span><span class="special">,</span><span class="string"> "f"</span><span class="special">);</span><span class="special"> }</span><span class="keyword">
|
||||
int</span><span class="identifier"> default_f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span><span class="special"> }</span><span class="comment"> // <<=== ***ADDED***
|
||||
</span><span class="identifier"> PyObject</span><span class="special">*</span><span class="identifier"> self</span><span class="special">;</span><span class="special">
|
||||
We wrap it this way:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">,</span><span class="identifier"> wrapper</span><span class="special"><</span><span class="identifier">Base</span><span class="special">></span><span class="special">
|
||||
{</span><span class="keyword">
|
||||
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special">
|
||||
{</span><span class="keyword">
|
||||
if</span><span class="special"> (</span><span class="identifier">override</span><span class="identifier"> f</span><span class="special"> =</span><span class="keyword"> this</span><span class="special">-></span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">))</span><span class="keyword">
|
||||
return</span><span class="identifier"> f</span><span class="special">();</span><span class="comment"> // *note*
|
||||
</span><span class="keyword"> return</span><span class="identifier"> Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span><span class="special">
|
||||
}</span><span class="keyword">
|
||||
|
||||
int</span><span class="identifier"> default_f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="keyword"> this</span><span class="special">-></span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span><span class="special"> }</span><span class="special">
|
||||
};</span></tt></pre>
|
||||
<p>
|
||||
Then, Boost.Python needs to keep track of 1) the dispatch function <tt class="literal">f</tt> and
|
||||
2) the forwarding function to its default implementation <tt class="literal">default_f</tt>.
|
||||
There's a special <tt class="literal">def</tt> function for this purpose. Here's how it is
|
||||
applied to our example above:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Base</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">>(</span><span class="string">"Base"</span><span class="special">)</span><span class="special">
|
||||
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="special"> &</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">,</span><span class="special"> &</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span><span class="special">)</span></tt></pre>
|
||||
Notice how we implemented <tt class="computeroutput"><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">f</span></tt>. Now, we have to check if there is an
|
||||
override for <tt class="computeroutput"><span class="identifier">f</span></tt>. If none, then we call <tt class="computeroutput"><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">()</span></tt>.</p>
|
||||
<div class="informaltable"><table class="table">
|
||||
<colgroup><col></colgroup>
|
||||
<tbody><tr><td>
|
||||
<span class="inlinemediaobject"><img src="../images/alert.png"></span> MSVC6/7 Workaround<p></p>
|
||||
<p></p>
|
||||
|
||||
If you are using Microsoft Visual C++ 6 or 7, you have to rewrite the line
|
||||
with the <tt class="computeroutput"><span class="special">*</span><span class="identifier">note</span><span class="special">*</span></tt> as:<p></p>
|
||||
<p></p>
|
||||
<tt class="computeroutput"><span class="keyword">return</span><span class="identifier"> call</span><span class="special"><</span><span class="keyword">char</span><span class="keyword"> const</span><span class="special">*>(</span><span class="identifier">f</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">());</span></tt>.</td></tr></tbody>
|
||||
</table></div>
|
||||
<p>
|
||||
Note that we are allowing <tt class="literal">Base</tt> objects to be instantiated this time,
|
||||
unlike before where we specifically defined the <tt class="literal">class_<Base></tt> with
|
||||
<tt class="literal">no_init</tt>.</p>
|
||||
Finally, exposing:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">>(</span><span class="string">"Base"</span><span class="special">)</span><span class="special">
|
||||
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="special"> &</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">,</span><span class="special"> &</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span><span class="special">)</span><span class="special">
|
||||
;</span></tt></pre>
|
||||
<p>
|
||||
Take note that we expose both <tt class="computeroutput"><span class="special">&</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span></tt> and <tt class="computeroutput"><span class="special">&</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span></tt>.
|
||||
Boost.Python needs to keep track of 1) the dispatch function <tt class="literal">f</tt> and 2) the
|
||||
forwarding function to its default implementation <tt class="literal">default_f</tt>. There's a
|
||||
special <tt class="literal">def</tt> function for this purpose.</p>
|
||||
<p>
|
||||
In Python, the results would be as expected:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="special">>>></span><span class="identifier"> base</span><span class="special"> =</span><span class="identifier"> Base</span><span class="special">()</span><span class="special">
|
||||
@@ -461,20 +391,12 @@ Calling <tt class="literal">base.f()</tt>:</p>
|
||||
Calling <tt class="literal">derived.f()</tt>:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="special">>>></span><span class="identifier"> derived</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span><span class="number">
|
||||
42</span></tt></pre>
|
||||
<p>
|
||||
Calling <tt class="literal">call_f</tt>, passing in a <tt class="literal">base</tt> object:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="special">>>></span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">base</span><span class="special">)</span><span class="number">
|
||||
0</span></tt></pre>
|
||||
<p>
|
||||
Calling <tt class="literal">call_f</tt>, passing in a <tt class="literal">derived</tt> object:</p>
|
||||
<pre class="programlisting"><tt class="literal"><span class="special">>>></span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">derived</span><span class="special">)</span><span class="number">
|
||||
42</span></tt></pre>
|
||||
</div>
|
||||
<div class="section" lang="en">
|
||||
<div class="titlepage"><div><div><h3 class="title">
|
||||
<a name="python.class_operators_special_functions"></a>Class Operators/Special Functions</h3></div></div></div>
|
||||
<a name="class_operators_special_functions.python_operators"></a><h2>
|
||||
<a name="id452701"></a>Python Operators</h2>
|
||||
<a name="id451830"></a>Python Operators</h2>
|
||||
<p>
|
||||
C is well known for the abundance of operators. C++ extends this to the
|
||||
extremes by allowing operator overloading. Boost.Python takes advantage of
|
||||
@@ -511,7 +433,7 @@ you might need to interact with in an operator expression is (cheaply)
|
||||
default-constructible. You can use <tt class="literal">other<T>()</tt> in place of an actual
|
||||
<tt class="literal">T</tt> instance when writing "self expressions".</p>
|
||||
<a name="class_operators_special_functions.special_methods"></a><h2>
|
||||
<a name="id453388"></a>Special Methods</h2>
|
||||
<a name="id452516"></a>Special Methods</h2>
|
||||
<p>
|
||||
Python has a few more <span class="emphasis"><em>Special Methods</em></span>. Boost.Python supports all of the
|
||||
standard special method names supported by real Python class instances. A
|
||||
|
||||
Reference in New Issue
Block a user