2
0
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:
Joel de Guzman
2004-11-15 06:34:34 +00:00
parent 3540d4fcf4
commit 168c8c692a

View File

@@ -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">&amp;</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">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</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">&amp;</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">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</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"> // &lt;&lt;=== ***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">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</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">-&gt;</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">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</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">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="keyword">this</span><span class="special">-&gt;</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">&lt;</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">&gt;(</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">(&amp;</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">&lt;</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">&gt;(</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">&gt;&gt;&gt;</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">&lt;</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">&gt;(</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">&gt;&gt;&gt;</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">&gt;&gt;&gt;</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">&gt;&gt;&gt;</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">&gt;&gt;&gt;</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&amp; 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&lt;int&gt;(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">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</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"> // &lt;&lt;=== ***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">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</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">-&gt;</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">-&gt;</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">&lt;</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">&gt;(</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"> &amp;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">,</span><span class="special"> &amp;</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">&lt;</span><span class="keyword">char</span><span class="keyword"> const</span><span class="special">*&gt;(</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_&lt;Base&gt;</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">&lt;</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">&gt;(</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"> &amp;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">,</span><span class="special"> &amp;</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">&amp;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span></tt> and <tt class="computeroutput"><span class="special">&amp;</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">&gt;&gt;&gt;</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">&gt;&gt;&gt;</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">&gt;&gt;&gt;</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">&gt;&gt;&gt;</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&lt;T&gt;()</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