mirror of
https://github.com/boostorg/python.git
synced 2026-01-19 16:32:16 +00:00
614 lines
54 KiB
HTML
614 lines
54 KiB
HTML
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||
<title> Exposing Classes</title>
|
||
<link rel="stylesheet" href="../boostbook.css" type="text/css">
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.66.1">
|
||
<link rel="start" href="../index.html" title="Chapter 1. python 1.0">
|
||
<link rel="up" href="../index.html" title="Chapter 1. python 1.0">
|
||
<link rel="prev" href="hello.html" title=" Building Hello World">
|
||
<link rel="next" href="functions.html" title="Functions">
|
||
</head>
|
||
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
||
<table cellpadding="2" width="100%">
|
||
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td>
|
||
<td align="center"><a href="../../../../../../../index.htm">Home</a></td>
|
||
<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td>
|
||
<td align="center"><a href="../../../../../../../people/people.htm">People</a></td>
|
||
<td align="center"><a href="../../../../../../../more/faq.htm">FAQ</a></td>
|
||
<td align="center"><a href="../../../../../../../more/index.htm">More</a></td>
|
||
</table>
|
||
<hr>
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="hello.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="functions.html"><img src="../images/next.png" alt="Next"></a>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
|
||
<a name="python.exposing"></a> Exposing Classes</h2></div></div></div>
|
||
<div class="toc"><dl>
|
||
<dt><span class="section"><a href="exposing.html#python.constructors">Constructors</a></span></dt>
|
||
<dt><span class="section"><a href="exposing.html#python.class_data_members">Class Data Members</a></span></dt>
|
||
<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.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>
|
||
<p>
|
||
Now let's expose a C++ class to Python.
|
||
</p>
|
||
<p>
|
||
Consider a C++ class/struct that we want to expose to Python:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">struct</span> <span class="identifier">World</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">void</span> <span class="identifier">set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">)</span> <span class="special">{</span> <span class="keyword">this</span><span class="special">-></span><span class="identifier">msg</span> <span class="special">=</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">greet</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">;</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
<p>
|
||
We can expose this to Python by writing a corresponding Boost.Python C++ Wrapper:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span>
|
||
|
||
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">class_</span><span class="special"><</span><span class="identifier">World</span><span class="special">>(</span><span class="string">"World"</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span>
|
||
<span class="special">;</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
Here, we wrote a C++ class wrapper that exposes the member functions <tt class="literal">greet</tt>
|
||
and <tt class="literal">set</tt>. Now, after building our module as a shared library,
|
||
we may use our class <tt class="literal">World</tt> in Python. Here's a sample Python
|
||
session:
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">hello</span>
|
||
<span class="special">>>></span> <span class="identifier">planet</span> <span class="special">=</span> <span class="identifier">hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span>
|
||
<span class="special">>>></span> <span class="identifier">planet</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="string">'howdy'</span><span class="special">)</span>
|
||
<span class="special">>>></span> <span class="identifier">planet</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span>
|
||
<span class="string">'howdy'</span>
|
||
</pre>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.constructors"></a>Constructors</h3></div></div></div>
|
||
<p>
|
||
Our previous example didn't have any explicit constructors. Since <tt class="literal">World</tt>
|
||
is declared as a plain struct, it has an implicit default constructor. Boost.Python
|
||
exposes the default constructor by default, which is why we were able to
|
||
write
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">>>></span> <span class="identifier">planet</span> <span class="special">=</span> <span class="identifier">hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span>
|
||
</pre>
|
||
<p>
|
||
We may wish to wrap a class with a non-default constructor. Let us build
|
||
on our previous example:
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">struct</span> <span class="identifier">World</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">World</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">):</span> <span class="identifier">msg</span><span class="special">(</span><span class="identifier">msg</span><span class="special">)</span> <span class="special">{}</span> <span class="comment">// added constructor
|
||
</span> <span class="keyword">void</span> <span class="identifier">set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">)</span> <span class="special">{</span> <span class="keyword">this</span><span class="special">-></span><span class="identifier">msg</span> <span class="special">=</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">greet</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">;</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
<p>
|
||
This time <tt class="literal">World</tt> has no default constructor; our previous
|
||
wrapping code would fail to compile when the library tried to expose it.
|
||
We have to tell <tt class="literal">class_<World></tt> about the constructor
|
||
we want to expose instead.
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span>
|
||
|
||
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">class_</span><span class="special"><</span><span class="identifier">World</span><span class="special">>(</span><span class="string">"World"</span><span class="special">,</span> <span class="identifier">init</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">>())</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span>
|
||
<span class="special">;</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
<tt class="literal">init<std::string>()</tt> exposes the constructor taking
|
||
in a <tt class="literal">std::string</tt> (in Python, constructors are spelled
|
||
"<tt class="literal">"<span class="underline">_init</span>_"</tt>").
|
||
</p>
|
||
<p>
|
||
We can expose additional constructors by passing more <tt class="literal">init<...></tt>s
|
||
to the <tt class="literal">def()</tt> member function. Say for example we have
|
||
another World constructor taking in two doubles:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">class_</span><span class="special"><</span><span class="identifier">World</span><span class="special">>(</span><span class="string">"World"</span><span class="special">,</span> <span class="identifier">init</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">>())</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special"><</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">double</span><span class="special">>())</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span>
|
||
<span class="special">;</span>
|
||
</pre>
|
||
<p>
|
||
On the other hand, if we do not wish to expose any constructors at all, we
|
||
may use <tt class="literal">no_init</tt> instead:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">class_</span><span class="special"><</span><span class="identifier">Abstract</span><span class="special">>(</span><span class="string">"Abstract"</span><span class="special">,</span> <span class="identifier">no_init</span><span class="special">)</span>
|
||
</pre>
|
||
<p>
|
||
This actually adds an <tt class="literal"><span class="underline">_init</span>_</tt>
|
||
method which always raises a Python RuntimeError exception.
|
||
</p>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.class_data_members"></a>Class Data Members</h3></div></div></div>
|
||
<p>
|
||
Data members may also be exposed to Python so that they can be accessed as
|
||
attributes of the corresponding Python class. Each data member that we wish
|
||
to be exposed may be regarded as <span class="bold"><b>read-only</b></span>
|
||
or <span class="bold"><b>read-write</b></span>. Consider this class <tt class="literal">Var</tt>:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">struct</span> <span class="identifier">Var</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">Var</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">name</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">name</span><span class="special">(</span><span class="identifier">name</span><span class="special">),</span> <span class="identifier">value</span><span class="special">()</span> <span class="special">{}</span>
|
||
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span> <span class="identifier">name</span><span class="special">;</span>
|
||
<span class="keyword">float</span> <span class="identifier">value</span><span class="special">;</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
<p>
|
||
Our C++ <tt class="literal">Var</tt> class and its data members can be exposed
|
||
to Python:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">class_</span><span class="special"><</span><span class="identifier">Var</span><span class="special">>(</span><span class="string">"Var"</span><span class="special">,</span> <span class="identifier">init</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">>())</span>
|
||
<span class="special">.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"name"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">name</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">def_readwrite</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">value</span><span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
Then, in Python, assuming we have placed our Var class inside the namespace
|
||
hello as we did before:
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">>>></span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">hello</span><span class="special">.</span><span class="identifier">Var</span><span class="special">(</span><span class="string">'pi'</span><span class="special">)</span>
|
||
<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span> <span class="special">=</span> <span class="number">3.14</span>
|
||
<span class="special">>>></span> <span class="keyword">print</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">name</span><span class="special">,</span> <span class="string">'is around'</span><span class="special">,</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span>
|
||
<span class="identifier">pi</span> <span class="keyword">is</span> <span class="identifier">around</span> <span class="number">3.14</span>
|
||
</pre>
|
||
<p>
|
||
Note that <tt class="literal">name</tt> is exposed as <span class="bold"><b>read-only</b></span>
|
||
while <tt class="literal">value</tt> is exposed as <span class="bold"><b>read-write</b></span>.
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">name</span> <span class="special">=</span> <span class="string">'e'</span> <span class="comment"># can't change name
|
||
</span><span class="identifier">Traceback</span> <span class="special">(</span><span class="identifier">most</span> <span class="identifier">recent</span> <span class="identifier">call</span> <span class="identifier">last</span><span class="special">):</span>
|
||
<span class="identifier">File</span> <span class="string">"<stdin>"</span><span class="special">,</span> <span class="identifier">line</span> <span class="number">1</span><span class="special">,</span> <span class="keyword">in</span> #
|
||
<span class="identifier">AttributeError</span><span class="special">:</span> <span class="identifier">can</span>#<span class="identifier">t</span> <span class="identifier">set</span> <span class="identifier">attribute</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.class_properties"></a>Class Properties</h3></div></div></div>
|
||
<p>
|
||
In C++, classes with public data members are usually frowned upon. Well designed
|
||
classes that take advantage of encapsulation hide the class' data members.
|
||
The only way to access the class' data is through access (getter/setter)
|
||
functions. Access functions expose class properties. Here's an example:
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">struct</span> <span class="identifier">Num</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">Num</span><span class="special">();</span>
|
||
<span class="keyword">float</span> <span class="identifier">get</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
|
||
<span class="keyword">void</span> <span class="identifier">set</span><span class="special">(</span><span class="keyword">float</span> <span class="identifier">value</span><span class="special">);</span>
|
||
<span class="special">...</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
<p>
|
||
However, in Python attribute access is fine; it doesn't neccessarily break
|
||
encapsulation to let users handle attributes directly, because the attributes
|
||
can just be a different syntax for a method call. Wrapping our <tt class="literal">Num</tt>
|
||
class using Boost.Python:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">class_</span><span class="special"><</span><span class="identifier">Num</span><span class="special">>(</span><span class="string">"Num"</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">set</span><span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
And at last, in Python:
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">>>></span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">Num</span><span class="special">()</span>
|
||
<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span> <span class="special">=</span> <span class="number">3.14</span>
|
||
<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span><span class="special">,</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">rovalue</span>
|
||
<span class="special">(</span><span class="number">3.14</span><span class="special">,</span> <span class="number">3.14</span><span class="special">)</span>
|
||
<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">rovalue</span> <span class="special">=</span> <span class="number">2.17</span> <span class="comment"># error!
|
||
</span></pre>
|
||
<p>
|
||
Take note that the class property <tt class="literal">rovalue</tt> is exposed as
|
||
<span class="bold"><b>read-only</b></span> since the <tt class="literal">rovalue</tt>
|
||
setter member function is not passed in:
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.inheritance"></a>Inheritance</h3></div></div></div>
|
||
<p>
|
||
In the previous examples, we dealt with classes that are not polymorphic.
|
||
This is not often the case. Much of the time, we will be wrapping polymorphic
|
||
classes and class hierarchies related by inheritance. We will often have
|
||
to write Boost.Python wrappers for classes that are derived from abstract
|
||
base classes.
|
||
</p>
|
||
<p>
|
||
Consider this trivial inheritance structure:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<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">struct</span> <span class="identifier">Derived</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{};</span>
|
||
</pre>
|
||
<p>
|
||
And a set of C++ functions operating on <tt class="literal">Base</tt> and <tt class="literal">Derived</tt>
|
||
object instances:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">void</span> <span class="identifier">b</span><span class="special">(</span><span class="identifier">Base</span><span class="special">*);</span>
|
||
<span class="keyword">void</span> <span class="identifier">d</span><span class="special">(</span><span class="identifier">Derived</span><span class="special">*);</span>
|
||
<span class="identifier">Base</span><span class="special">*</span> <span class="identifier">factory</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="keyword">new</span> <span class="identifier">Derived</span><span class="special">;</span> <span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
We've seen how we can wrap the base class <tt class="literal">Base</tt>:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">class_</span><span class="special"><</span><span class="identifier">Base</span><span class="special">>(</span><span class="string">"Base"</span><span class="special">)</span>
|
||
<span class="comment">/*...*/</span>
|
||
<span class="special">;</span>
|
||
</pre>
|
||
<p>
|
||
Now we can inform Boost.Python of the inheritance relationship between <tt class="literal">Derived</tt>
|
||
and its base class <tt class="literal">Base</tt>. Thus:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">class_</span><span class="special"><</span><span class="identifier">Derived</span><span class="special">,</span> <span class="identifier">bases</span><span class="special"><</span><span class="identifier">Base</span><span class="special">></span> <span class="special">>(</span><span class="string">"Derived"</span><span class="special">)</span>
|
||
<span class="comment">/*...*/</span>
|
||
<span class="special">;</span>
|
||
</pre>
|
||
<p>
|
||
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)
|
||
</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.
|
||
</li>
|
||
</ol></div>
|
||
<p>
|
||
Now, we shall expose the C++ free functions <tt class="literal">b</tt> and <tt class="literal">d</tt>
|
||
and <tt class="literal">factory</tt>:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">def</span><span class="special">(</span><span class="string">"b"</span><span class="special">,</span> <span class="identifier">b</span><span class="special">);</span>
|
||
<span class="identifier">def</span><span class="special">(</span><span class="string">"d"</span><span class="special">,</span> <span class="identifier">d</span><span class="special">);</span>
|
||
<span class="identifier">def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span> <span class="identifier">factory</span><span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
Note that free function <tt class="literal">factory</tt> is being used to generate
|
||
new instances of class <tt class="literal">Derived</tt>. In such cases, we use
|
||
<tt class="literal">return_value_policy<manage_new_object></tt> to instruct
|
||
Python to adopt the pointer to <tt class="literal">Base</tt> and hold the instance
|
||
in a new Python <tt class="literal">Base</tt> object until the the Python object
|
||
is destroyed. We shall see more of Boost.Python <a href="functions.html#python.call_policies" title="Call Policies">call
|
||
policies</a> later.
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="comment">// Tell Python to take ownership of factory's result
|
||
</span><span class="identifier">def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span> <span class="identifier">factory</span><span class="special">,</span>
|
||
<span class="identifier">return_value_policy</span><span class="special"><</span><span class="identifier">manage_new_object</span><span class="special">>());</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<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>
|
||
<pre class="programlisting">
|
||
<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>
|
||
</pre>
|
||
<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. 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">
|
||
<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>
|
||
</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 class="blurb"> <span class="inlinemediaobject"><img src="../images/alert.png" alt="alert"></span> <span class="bold"><b>MSVC6/7 Workaround</b></span><br>
|
||
<br> If you are using Microsoft Visual C++ 6 or 7, you have to write
|
||
<tt class="computeroutput"><span class="identifier">f</span></tt> as:<br> <br>
|
||
<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">
|
||
<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>
|
||
</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 class="blurb"> <span class="inlinemediaobject"><img src="../images/note.png" alt="note"></span> <span class="bold"><b>member function and
|
||
methods</b></span><br> <br> Python, like many object oriented languages
|
||
uses the term <span class="bold"><b>methods</b></span>. Methods correspond
|
||
roughly to C++'s <span class="bold"><b>member functions</b></span>
|
||
</td></tr></tbody>
|
||
</table></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>
|
||
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">
|
||
<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">};</span>
|
||
</pre>
|
||
<p>
|
||
had a pure virtual function <tt class="literal">f</tt>. If, however, its member
|
||
function <tt class="literal">f</tt> was not declared as pure virtual:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<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>
|
||
</pre>
|
||
<p>
|
||
We wrap it this way:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<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>
|
||
</pre>
|
||
<p>
|
||
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 class="blurb"> <span class="inlinemediaobject"><img src="../images/alert.png" alt="alert"></span> <span class="bold"><b>MSVC6/7 Workaround</b></span><br>
|
||
<br> 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:<br> <br> <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>
|
||
Finally, exposing:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<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>
|
||
</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>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting">
|
||
<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">>>></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="keyword">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>
|
||
<span class="special">>>></span> <span class="identifier">derived</span> <span class="special">=</span> <span class="identifier">Derived</span><span class="special">()</span>
|
||
</pre>
|
||
<p>
|
||
Calling <tt class="literal">base.f()</tt>:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">>>></span> <span class="identifier">base</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span>
|
||
<span class="number">0</span>
|
||
</pre>
|
||
<p>
|
||
Calling <tt class="literal">derived.f()</tt>:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<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>
|
||
</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="id448928"></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 this and
|
||
makes it easy to wrap C++ operator-powered classes.
|
||
</p>
|
||
<p>
|
||
Consider a file position class <tt class="literal">FilePos</tt> and a set of operators
|
||
that take on FilePos instances:
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">class</span> <span class="identifier">FilePos</span> <span class="special">{</span> <span class="comment">/*...*/</span> <span class="special">};</span>
|
||
|
||
<span class="identifier">FilePos</span> <span class="keyword">operator</span><span class="special">+(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="keyword">int</span><span class="special">);</span>
|
||
<span class="identifier">FilePos</span> <span class="keyword">operator</span><span class="special">+(</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">FilePos</span><span class="special">);</span>
|
||
<span class="keyword">int</span> <span class="keyword">operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="identifier">FilePos</span><span class="special">);</span>
|
||
<span class="identifier">FilePos</span> <span class="keyword">operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="keyword">int</span><span class="special">);</span>
|
||
<span class="identifier">FilePos</span><span class="special">&</span> <span class="keyword">operator</span><span class="special">+=(</span><span class="identifier">FilePos</span><span class="special">&,</span> <span class="keyword">int</span><span class="special">);</span>
|
||
<span class="identifier">FilePos</span><span class="special">&</span> <span class="keyword">operator</span><span class="special">-=(</span><span class="identifier">FilePos</span><span class="special">&,</span> <span class="keyword">int</span><span class="special">);</span>
|
||
<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special"><(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="identifier">FilePos</span><span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
The class and the various operators can be mapped to Python rather easily
|
||
and intuitively:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">class_</span><span class="special"><</span><span class="identifier">FilePos</span><span class="special">>(</span><span class="string">"FilePos"</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">+</span> <span class="keyword">int</span><span class="special">())</span> <span class="comment">// __add__
|
||
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="keyword">int</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">self</span><span class="special">)</span> <span class="comment">// __radd__
|
||
</span> <span class="special">.</span><span class="identifier">def</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="comment">// __sub__
|
||
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">-</span> <span class="keyword">int</span><span class="special">())</span> <span class="comment">// __sub__
|
||
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">+=</span> <span class="keyword">int</span><span class="special">())</span> <span class="comment">// __iadd__
|
||
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">-=</span> <span class="identifier">other</span><span class="special"><</span><span class="keyword">int</span><span class="special">>())</span>
|
||
<span class="special">.</span><span class="identifier">def</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="comment">// __lt__
|
||
</span></pre>
|
||
<p>
|
||
The code snippet above is very clear and needs almost no explanation at all.
|
||
It is virtually the same as the operators' signatures. Just take note that
|
||
<tt class="literal">self</tt> refers to FilePos object. Also, not every class
|
||
<tt class="literal">T</tt> that 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="id449680"></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 similar set of intuitive interfaces can also be used to
|
||
wrap C++ functions that correspond to these Python <span class="emphasis"><em>special functions</em></span>.
|
||
Example:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">class</span> <span class="identifier">Rational</span>
|
||
<span class="special">{</span> <span class="keyword">public</span><span class="special">:</span> <span class="keyword">operator</span> <span class="keyword">double</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span> <span class="special">};</span>
|
||
|
||
<span class="identifier">Rational</span> <span class="identifier">pow</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">,</span> <span class="identifier">Rational</span><span class="special">);</span>
|
||
<span class="identifier">Rational</span> <span class="identifier">abs</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">);</span>
|
||
<span class="identifier">ostream</span><span class="special">&</span> <span class="keyword">operator</span><span class="special"><<(</span><span class="identifier">ostream</span><span class="special">&,</span><span class="identifier">Rational</span><span class="special">);</span>
|
||
|
||
<span class="identifier">class_</span><span class="special"><</span><span class="identifier">Rational</span><span class="special">>(</span><span class="string">"Rational"</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">float_</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span> <span class="comment">// __float__
|
||
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">pow</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span> <span class="identifier">other</span><span class="special"><</span><span class="identifier">Rational</span><span class="special">>))</span> <span class="comment">// __pow__
|
||
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">abs</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span> <span class="comment">// __abs__
|
||
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">str</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span> <span class="comment">// __str__
|
||
</span> <span class="special">;</span>
|
||
</pre>
|
||
<p>
|
||
Need we say more?
|
||
</p>
|
||
<div class="informaltable"><table class="table">
|
||
<colgroup><col></colgroup>
|
||
<tbody><tr><td class="blurb"> <span class="inlinemediaobject"><img src="../images/note.png" alt="note"></span> What is the business of <tt class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></tt>? Well, the method <tt class="computeroutput"><span class="identifier">str</span></tt> requires the <tt class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></tt> to do its work (i.e. <tt class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></tt>
|
||
is used by the method defined by <tt class="computeroutput"><span class="identifier">def</span><span class="special">(</span><span class="identifier">str</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span></tt>.</td></tr></tbody>
|
||
</table></div>
|
||
</div>
|
||
</div>
|
||
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
|
||
<td align="left"></td>
|
||
<td align="right"><small>Copyright © 2002-2005 Joel
|
||
de Guzman, David Abrahams</small></td>
|
||
</tr></table>
|
||
<hr>
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="hello.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="functions.html"><img src="../images/next.png" alt="Next"></a>
|
||
</div>
|
||
</body>
|
||
</html>
|