mirror of
https://github.com/boostorg/python.git
synced 2026-01-23 17:52:17 +00:00
Tutorial updates. Added virtual functions with default implementations and reshufled the overloading topics to discuss manual overloading first.
[SVN r17597]
This commit is contained in:
112
doc/tutorial/doc/auto_overloading.html
Normal file
112
doc/tutorial/doc/auto_overloading.html
Normal file
@@ -0,0 +1,112 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Auto-Overloading</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="default_arguments.html">
|
||||
<link rel="next" href="object_interface.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="theme/c%2B%2Bboost.gif">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Auto-Overloading</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="default_arguments.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="object_interface.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
It was mentioned in passing in the previous section that
|
||||
<tt>BOOST_PYTHON_FUNCTION_OVERLOADS</tt> and <tt>BOOST_PYTHON_FUNCTION_OVERLOADS</tt>
|
||||
can also be used for overloaded functions and member functions with a
|
||||
common sequence of initial arguments. Here is an example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>void </span><span class=identifier>foo</span><span class=special>()
|
||||
{
|
||||
/*...*/
|
||||
}
|
||||
|
||||
</span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>bool </span><span class=identifier>a</span><span class=special>)
|
||||
{
|
||||
/*...*/
|
||||
}
|
||||
|
||||
</span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>bool </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>b</span><span class=special>)
|
||||
{
|
||||
/*...*/
|
||||
}
|
||||
|
||||
</span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>bool </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>b</span><span class=special>, </span><span class=keyword>char </span><span class=identifier>c</span><span class=special>)
|
||||
{
|
||||
/*...*/
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Like in the previous section, we can generate thin wrappers for these
|
||||
overloaded functions in one-shot:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class=special>(</span><span class=identifier>foo_overloads</span><span class=special>, </span><span class=identifier>foo</span><span class=special>, </span><span class=number>0</span><span class=special>, </span><span class=number>3</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Then...</p>
|
||||
<code><pre>
|
||||
<span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"foo"</span><span class=special>, </span><span class=identifier>foo</span><span class=special>, </span><span class=identifier>foo_overloads</span><span class=special>());
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Notice though that we have a situation now where we have a minimum of zero
|
||||
(0) arguments and a maximum of 3 arguments.</p>
|
||||
<a name="manual_wrapping"></a><h2>Manual Wrapping</h2><p>
|
||||
It is important to emphasize however that <b>the overloaded functions must
|
||||
have a common sequence of initial arguments</b>. Otherwise, our scheme above
|
||||
will not work. If this is not the case, we have to wrap our functions
|
||||
<a href="overloading.html">
|
||||
manually</a>.</p>
|
||||
<p>
|
||||
Actually, we can mix and match manual wrapping of overloaded functions and
|
||||
automatic wrapping through <tt>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> and
|
||||
its sister, <tt>BOOST_PYTHON_FUNCTION_OVERLOADS</tt>. Following up on our example
|
||||
presented in the section <a href="overloading.html">
|
||||
on overloading</a>, since the
|
||||
first overload has default arguments, we can use
|
||||
<tt>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> to automatically wrap the first
|
||||
three of the <tt>def</tt>s above and manually wrap just the last. Here's how
|
||||
we'll do this:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class=special>(</span><span class=identifier>xf_overloads</span><span class=special>, </span><span class=identifier>f</span><span class=special>, </span><span class=number>1</span><span class=special>, </span><span class=number>4</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Create a member function pointers as above for both X::f overloads:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>bool </span><span class=special>(</span><span class=identifier>X</span><span class=special>::*</span><span class=identifier>fx1</span><span class=special>)(</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>double</span><span class=special>, </span><span class=keyword>char</span><span class=special>) = &</span><span class=identifier>X</span><span class=special>::</span><span class=identifier>f</span><span class=special>;
|
||||
</span><span class=keyword>int </span><span class=special>(</span><span class=identifier>X</span><span class=special>::*</span><span class=identifier>fx2</span><span class=special>)(</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>int</span><span class=special>, </span><span class=keyword>int</span><span class=special>) = &</span><span class=identifier>X</span><span class=special>::</span><span class=identifier>f</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Then...</p>
|
||||
<code><pre>
|
||||
<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>fx1</span><span class=special>, </span><span class=identifier>xf_overloads</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>fx2</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="default_arguments.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="object_interface.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -4,7 +4,7 @@
|
||||
<title>Call Policies</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="functions.html">
|
||||
<link rel="next" href="default_arguments.html">
|
||||
<link rel="next" href="overloading.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
@@ -21,7 +21,7 @@
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="default_arguments.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
@@ -156,7 +156,7 @@ here</a>.</p>
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="default_arguments.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Class Operators/Special Functions</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="class_virtual_functions.html">
|
||||
<link rel="prev" href="virtual_functions_with_default_implementations.html">
|
||||
<link rel="next" href="functions.html">
|
||||
</head>
|
||||
<body>
|
||||
@@ -20,7 +20,7 @@
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="class_virtual_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="virtual_functions_with_default_implementations.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -95,7 +95,7 @@ Well, the method <tt>str</tt> requires the <tt>operator<<</tt> to do its w
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="class_virtual_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="virtual_functions_with_default_implementations.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<title>Class Virtual Functions</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="inheritance.html">
|
||||
<link rel="next" href="class_operators_special_functions.html">
|
||||
<link rel="next" href="deriving_a_python_class.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
@@ -21,7 +21,7 @@
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="inheritance.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="class_operators_special_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="deriving_a_python_class.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
@@ -112,118 +112,11 @@ In Python, let us try to instantiate our <tt>Base</tt> class:</p>
|
||||
Why is it an error? <tt>Base</tt> is an abstract class. As such it is advisable
|
||||
to define the Python wrapper with <tt>no_init</tt> as we have done above. Doing
|
||||
so will disallow abstract base classes such as <tt>Base</tt> to be instantiated.</p>
|
||||
<a name="deriving_a_python_class"></a><h2>Deriving a Python class</h2><p>
|
||||
Now, at last, we can even derive from our base class Base in Python. Before
|
||||
we can do that, we have to set up our class_ wrapper as:</p>
|
||||
<code><pre>
|
||||
<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></pre></code>
|
||||
<p>
|
||||
Otherwise, we have to suppress the Base class' <tt>no_init</tt> by adding an
|
||||
<tt>__init__()</tt> method to all our derived classes. <tt>no_init</tt> actually adds
|
||||
an <tt>__init__</tt> method that raises a Python RuntimeError exception.</p>
|
||||
<code><pre>
|
||||
<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=identifier>def </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>self</span><span class=special>):
|
||||
... </span><span class=keyword>return </span><span class=number>42
|
||||
</span><span class=special>...
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Cool eh? A Python class deriving from a C++ class!</p>
|
||||
<p>
|
||||
Let's now make an instance of our Python class <tt>Derived</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=special>>>> </span><span class=identifier>derived </span><span class=special>= </span><span class=identifier>Derived</span><span class=special>()
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Calling <tt>derived.f()</tt>:</p>
|
||||
<code><pre>
|
||||
<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></code>
|
||||
<p>
|
||||
Will yield the expected result. Finally, calling calling the free function
|
||||
<tt>call_f</tt> with <tt>derived</tt> as argument:</p>
|
||||
<code><pre>
|
||||
<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></pre></code>
|
||||
<p>
|
||||
Will also yield the expected result.</p>
|
||||
<p>
|
||||
Here's what's happening:</p>
|
||||
<ol><li><tt>call_f(derived)</tt> is called in Python</li><li>This corresponds to <tt>def("call_f", call_f);</tt>. Boost.Python dispatches this call.</li><li><tt>int call_f(Base& b) { return b.f(); }</tt> accepts the call.</li><li>The overridden virtual function <tt>f</tt> of <tt>BaseWrap</tt> is called.</li><li><tt>call_method<int>(self, "f");</tt> dispatches the call back to Python.</li><li><tt>def f(self): return 42</tt> is finally called.</li></ol><p>
|
||||
Rewind back to our <tt>Base</tt> class, if its member function <tt>f</tt> was not
|
||||
declared as pure virtual:</p>
|
||||
<code><pre>
|
||||
<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=keyword>return </span><span class=number>0</span><span class=special>; }
|
||||
};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
And instead is implemented to return <tt>0</tt>, as shown above.</p>
|
||||
<code><pre>
|
||||
<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=identifier>self</span><span class=special>(</span><span class=identifier>self_</span><span class=special>) {}
|
||||
</span><span class=keyword>int </span><span class=identifier>f</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=keyword>static </span><span class=keyword>int </span><span class=identifier>default_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=keyword>return </span><span class=identifier>b</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=identifier>added
|
||||
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>self</span><span class=special>;
|
||||
};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
then, our Boost.Python wrapper:</p>
|
||||
<code><pre>
|
||||
<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=string>"Base"</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>BaseWrap</span><span class=special>::</span><span class=identifier>default_f</span><span class=special>)
|
||||
;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Note that we are allowing <tt>Base</tt> objects to be instantiated this time,
|
||||
unlike before where we specifically defined the <tt>class_<Base></tt> with
|
||||
<tt>no_init</tt>.</p>
|
||||
<p>
|
||||
In Python, the results would be as expected:</p>
|
||||
<code><pre>
|
||||
<span class=special>>>> </span><span class=identifier>base </span><span class=special>= </span><span class=identifier>Base</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=identifier>def </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>self</span><span class=special>):
|
||||
... </span><span class=keyword>return </span><span class=number>42
|
||||
</span><span class=special>...
|
||||
>>> </span><span class=identifier>derived </span><span class=special>= </span><span class=identifier>Derived</span><span class=special>()
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Calling <tt>base.f()</tt>:</p>
|
||||
<code><pre>
|
||||
<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></code>
|
||||
<p>
|
||||
Calling <tt>derived.f()</tt>:</p>
|
||||
<code><pre>
|
||||
<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></code>
|
||||
<p>
|
||||
Calling <tt>call_f</tt>, passing in a <tt>base</tt> object:</p>
|
||||
<code><pre>
|
||||
<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></pre></code>
|
||||
<p>
|
||||
Calling <tt>call_f</tt>, passing in a <tt>derived</tt> object:</p>
|
||||
<code><pre>
|
||||
<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></pre></code>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="inheritance.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="class_operators_special_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="deriving_a_python_class.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Default Arguments</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="call_policies.html">
|
||||
<link rel="next" href="overloading.html">
|
||||
<link rel="prev" href="overloading.html">
|
||||
<link rel="next" href="auto_overloading.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
@@ -20,8 +20,8 @@
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="call_policies.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="overloading.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="auto_overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
@@ -44,8 +44,10 @@ to retrieve the default arguments:</p>
|
||||
<span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>f</span><span class=special>); // </span><span class=identifier>defaults </span><span class=identifier>lost</span><span class=special>!
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Because of this, when wrapping C++ code in earlier versions of
|
||||
Boost.Python, we had to resort to writing thin wrappers:</p>
|
||||
Because of this, when wrapping C++ code, we had to resort to manual
|
||||
wrapping as outlined in the <a href="overloading.html">
|
||||
previous section</a>, or
|
||||
writing thin wrappers:</p>
|
||||
<code><pre>
|
||||
<span class=comment>// write "thin wrappers"
|
||||
</span><span class=keyword>int </span><span class=identifier>f1</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>x</span><span class=special>) { </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>x</span><span class=special>); }
|
||||
@@ -142,8 +144,8 @@ Notice the use of <tt>init<...></tt> and <tt>optional<...></tt> to s
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="call_policies.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="overloading.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="auto_overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
|
||||
82
doc/tutorial/doc/deriving_a_python_class.html
Normal file
82
doc/tutorial/doc/deriving_a_python_class.html
Normal file
@@ -0,0 +1,82 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Deriving a Python Class</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="class_virtual_functions.html">
|
||||
<link rel="next" href="virtual_functions_with_default_implementations.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="theme/c%2B%2Bboost.gif">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Deriving a Python Class</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="class_virtual_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="virtual_functions_with_default_implementations.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Continuing, now, at last, we can even derive from our base class Base in
|
||||
Python. Before we can do that, we have to set up our <tt>class_</tt> wrapper as:</p>
|
||||
<code><pre>
|
||||
<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></pre></code>
|
||||
<p>
|
||||
Otherwise, we have to suppress the Base class' <tt>no_init</tt> by adding an
|
||||
<tt>__init__()</tt> method to all our derived classes. <tt>no_init</tt> actually adds
|
||||
an <tt>__init__</tt> method that raises a Python RuntimeError exception.</p>
|
||||
<code><pre>
|
||||
<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=identifier>def </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>self</span><span class=special>):
|
||||
... </span><span class=keyword>return </span><span class=number>42
|
||||
</span><span class=special>...
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Cool eh? A Python class deriving from a C++ class!</p>
|
||||
<p>
|
||||
Let's now make an instance of our Python class <tt>Derived</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=special>>>> </span><span class=identifier>derived </span><span class=special>= </span><span class=identifier>Derived</span><span class=special>()
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Calling <tt>derived.f()</tt>:</p>
|
||||
<code><pre>
|
||||
<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></code>
|
||||
<p>
|
||||
Will yield the expected result. Finally, calling calling the free function
|
||||
<tt>call_f</tt> with <tt>derived</tt> as argument:</p>
|
||||
<code><pre>
|
||||
<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></pre></code>
|
||||
<p>
|
||||
Will also yield the expected result.</p>
|
||||
<p>
|
||||
Here's what's happening:</p>
|
||||
<ol><li><tt>call_f(derived)</tt> is called in Python</li><li>This corresponds to <tt>def("call_f", call_f);</tt>. Boost.Python dispatches this call.</li><li><tt>int call_f(Base& b) { return b.f(); }</tt> accepts the call.</li><li>The overridden virtual function <tt>f</tt> of <tt>BaseWrap</tt> is called.</li><li><tt>call_method<int>(self, "f");</tt> dispatches the call back to Python.</li><li><tt>def f(self): return 42</tt> is finally called.</li></ol><table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="class_virtual_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="virtual_functions_with_default_implementations.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,7 +3,7 @@
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Object Interface</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="overloading.html">
|
||||
<link rel="prev" href="auto_overloading.html">
|
||||
<link rel="next" href="basic_interface.html">
|
||||
</head>
|
||||
<body>
|
||||
@@ -20,7 +20,7 @@
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="overloading.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="auto_overloading.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="basic_interface.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -40,7 +40,7 @@ should minimize the learning curve significantly.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="overloading.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="auto_overloading.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="basic_interface.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Overloading</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="default_arguments.html">
|
||||
<link rel="next" href="object_interface.html">
|
||||
<link rel="prev" href="call_policies.html">
|
||||
<link rel="next" href="default_arguments.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
@@ -20,59 +20,16 @@
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="default_arguments.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="object_interface.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="call_policies.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="default_arguments.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
It was mentioned in passing in the previous section that
|
||||
<tt>BOOST_PYTHON_FUNCTION_OVERLOADS</tt> and <tt>BOOST_PYTHON_FUNCTION_OVERLOADS</tt>
|
||||
can also be used for overloaded functions and member functions with a
|
||||
common sequence of initial arguments. Here is an example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>void </span><span class=identifier>foo</span><span class=special>()
|
||||
{
|
||||
/*...*/
|
||||
}
|
||||
|
||||
</span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>bool </span><span class=identifier>a</span><span class=special>)
|
||||
{
|
||||
/*...*/
|
||||
}
|
||||
|
||||
</span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>bool </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>b</span><span class=special>)
|
||||
{
|
||||
/*...*/
|
||||
}
|
||||
|
||||
</span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>bool </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>b</span><span class=special>, </span><span class=keyword>char </span><span class=identifier>c</span><span class=special>)
|
||||
{
|
||||
/*...*/
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Like in the previous section, we can generate thin wrappers for these
|
||||
overloaded functions in one-shot:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class=special>(</span><span class=identifier>foo_overloads</span><span class=special>, </span><span class=identifier>foo</span><span class=special>, </span><span class=number>0</span><span class=special>, </span><span class=number>3</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Then...</p>
|
||||
<code><pre>
|
||||
<span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"foo"</span><span class=special>, </span><span class=identifier>foo</span><span class=special>, </span><span class=identifier>foo_overloads</span><span class=special>());
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Notice though that we have a situation now where we have a minimum of zero
|
||||
(0) arguments and a maximum of 3 arguments.</p>
|
||||
<a name="manual_wrapping"></a><h2>Manual Wrapping</h2><p>
|
||||
It is important to emphasize however that <b>the overloaded functions must
|
||||
have a common sequence of initial arguments</b>. Otherwise, our scheme above
|
||||
will not work.</p>
|
||||
<p>
|
||||
The following illustrates an alternate scheme for manually wrapping an
|
||||
overloaded member function instead of
|
||||
<tt>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>. Obviously, the same technique
|
||||
can be applied to wrapping overloaded non- member functions.</p>
|
||||
The following illustrates a scheme for manually wrapping an overloaded
|
||||
member function or. Obviously, the same technique can be applied to
|
||||
wrapping overloaded non- member functions. Take note that this scheme
|
||||
applies to actual overloaded (member, non-member) functions as well as
|
||||
(member, non-member) functions with default arguments.</p>
|
||||
<p>
|
||||
We have here our C++ classes:</p>
|
||||
<code><pre>
|
||||
@@ -113,33 +70,11 @@ With these in hand, we can proceed to define and wrap this for Python:</p>
|
||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>fx3</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>fx4</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Actually, we can mix and match manual wrapping of overloaded functions and
|
||||
automatic wrapping through <tt>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> and
|
||||
its sister, <tt>BOOST_PYTHON_FUNCTION_OVERLOADS</tt>. Since the first overload
|
||||
has default arguments, we can use <tt>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>
|
||||
to automatically wrap the first three of the <tt>def</tt>s above and manually
|
||||
wrap just the last. Here's how we'll do this:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class=special>(</span><span class=identifier>xf_overloads</span><span class=special>, </span><span class=identifier>f</span><span class=special>, </span><span class=number>1</span><span class=special>, </span><span class=number>4</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Create a member function pointers as above for both X::f overloads:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>bool </span><span class=special>(</span><span class=identifier>X</span><span class=special>::*</span><span class=identifier>fx1</span><span class=special>)(</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>double</span><span class=special>, </span><span class=keyword>char</span><span class=special>) = &</span><span class=identifier>X</span><span class=special>::</span><span class=identifier>f</span><span class=special>;
|
||||
</span><span class=keyword>int </span><span class=special>(</span><span class=identifier>X</span><span class=special>::*</span><span class=identifier>fx2</span><span class=special>)(</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>int</span><span class=special>, </span><span class=keyword>int</span><span class=special>) = &</span><span class=identifier>X</span><span class=special>::</span><span class=identifier>f</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Then...</p>
|
||||
<code><pre>
|
||||
<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>fx1</span><span class=special>, </span><span class=identifier>xf_overloads</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>fx2</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="default_arguments.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="object_interface.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="call_policies.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="default_arguments.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
|
||||
@@ -527,10 +527,10 @@ Why is it an error? [^Base] is an abstract class. As such it is advisable
|
||||
to define the Python wrapper with [^no_init] as we have done above. Doing
|
||||
so will disallow abstract base classes such as [^Base] to be instantiated.
|
||||
|
||||
[h2 Deriving a Python class]
|
||||
[page:1 Deriving a Python Class]
|
||||
|
||||
Now, at last, we can even derive from our base class Base in Python. Before
|
||||
we can do that, we have to set up our class_ wrapper as:
|
||||
Continuing, now, at last, we can even derive from our base class Base in
|
||||
Python. Before we can do that, we have to set up our [^class_] wrapper as:
|
||||
|
||||
class_<Base, BaseWrap, boost::noncopyable>("Base")
|
||||
;
|
||||
@@ -572,30 +572,45 @@ Here's what's happening:
|
||||
# [^call_method<int>(self, "f");] dispatches the call back to Python.
|
||||
# [^def f(self): return 42] is finally called.
|
||||
|
||||
Rewind back to our [^Base] class, if its member function [^f] was not
|
||||
declared as pure virtual:
|
||||
[page:1 Virtual Functions with Default Implementations]
|
||||
|
||||
Recall that in the [@class_virtual_functions.html previous section], we
|
||||
wrapped a class with a pure virtual function that we then implemented in
|
||||
C++ or Python classes derived from it. Our base class:
|
||||
|
||||
struct Base
|
||||
{
|
||||
virtual int f() = 0;
|
||||
};
|
||||
|
||||
had a pure virtual function [^f]. If, however, its member function [^f] was
|
||||
not declared as pure virtual:
|
||||
|
||||
struct Base
|
||||
{
|
||||
virtual int f() { return 0; }
|
||||
};
|
||||
|
||||
And instead is implemented to return [^0], as shown above.
|
||||
and instead had a default implementation that returns [^0], as shown above,
|
||||
we need to add a forwarding function that calls the [^Base] default virtual
|
||||
function [^f] implementation:
|
||||
|
||||
struct BaseWrap : Base
|
||||
{
|
||||
BaseWrap(PyObject* self_)
|
||||
: self(self_) {}
|
||||
int f() { return call_method<int>(self, "f"); }
|
||||
static int default_f(Base* b) { return b->Base::f(); } // <<=== added
|
||||
int default_f() { return Base::f(); } // <<=== ***ADDED***
|
||||
PyObject* self;
|
||||
};
|
||||
|
||||
then, our Boost.Python wrapper:
|
||||
Then, Boost.Python needs to keep track of 1) the dispatch function [^f] and
|
||||
2) the forwarding function to its default implementation [^default_f].
|
||||
There's a special [^def] function for this purpose. Here's how it is
|
||||
applied to our example above:
|
||||
|
||||
class_<Base, BaseWrap>("Base")
|
||||
.def("f", &BaseWrap::default_f)
|
||||
;
|
||||
.def("f", &Base::f, &BaseWrap::default_f)
|
||||
|
||||
Note that we are allowing [^Base] objects to be instantiated this time,
|
||||
unlike before where we specifically defined the [^class_<Base>] with
|
||||
@@ -874,6 +889,51 @@ these can be found [@../../v2/reference.html#models_of_call_policies here].
|
||||
"Explicit is better than implicit"[br]
|
||||
"In the face of ambiguity, refuse the temptation to guess"[br]]
|
||||
|
||||
[page:1 Overloading]
|
||||
|
||||
The following illustrates a scheme for manually wrapping an overloaded
|
||||
member function or. Obviously, the same technique can be applied to
|
||||
wrapping overloaded non- member functions. Take note that this scheme
|
||||
applies to actual overloaded (member, non-member) functions as well as
|
||||
(member, non-member) functions with default arguments.
|
||||
|
||||
We have here our C++ classes:
|
||||
|
||||
struct X
|
||||
{
|
||||
bool f(int a, double b = 0, char c = 'x')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int f(int a, int b, int c)
|
||||
{
|
||||
return a + b + c;
|
||||
};
|
||||
};
|
||||
|
||||
Notice that class X has two overloaded functions with different signatures.
|
||||
The types of the arguments, and the return are totally different, unlike
|
||||
above where we have a common sequence of initial arguments.
|
||||
|
||||
We shall start by introducing some member function pointer variables:
|
||||
|
||||
bool (X::*fx1)(int) = &X::f;
|
||||
bool (X::*fx2)(int, double) = &X::f;
|
||||
bool (X::*fx3)(int, double, char)= &X::f;
|
||||
int (X::*fx4)(int, int, int) = &X::f;
|
||||
|
||||
The first three member function pointers take care of the first X::f
|
||||
overload. The one with default arguments. The last member function pointer
|
||||
takes care of the second X::f overload.
|
||||
|
||||
With these in hand, we can proceed to define and wrap this for Python:
|
||||
|
||||
.def("f", fx1)
|
||||
.def("f", fx2)
|
||||
.def("f", fx3)
|
||||
.def("f", fx4)
|
||||
|
||||
[page:1 Default Arguments]
|
||||
|
||||
Boost.Python wraps (member) function pointers. Unfortunately, C++ function
|
||||
@@ -892,8 +952,9 @@ to retrieve the default arguments:
|
||||
|
||||
def("f", f); // defaults lost!
|
||||
|
||||
Because of this, when wrapping C++ code in earlier versions of
|
||||
Boost.Python, we had to resort to writing thin wrappers:
|
||||
Because of this, when wrapping C++ code, we had to resort to manual
|
||||
wrapping as outlined in the [@overloading.html previous section], or
|
||||
writing thin wrappers:
|
||||
|
||||
// write "thin wrappers"
|
||||
int f1(int x) { f(x); }
|
||||
@@ -987,7 +1048,7 @@ You can easily add this constructor to Boost.Python in one shot:
|
||||
Notice the use of [^init<...>] and [^optional<...>] to signify the default
|
||||
(optional arguments).
|
||||
|
||||
[page:1 Overloading]
|
||||
[page:1 Auto-Overloading]
|
||||
|
||||
It was mentioned in passing in the previous section that
|
||||
[^BOOST_PYTHON_FUNCTION_OVERLOADS] and [^BOOST_PYTHON_FUNCTION_OVERLOADS]
|
||||
@@ -1030,56 +1091,17 @@ Notice though that we have a situation now where we have a minimum of zero
|
||||
|
||||
It is important to emphasize however that [*the overloaded functions must
|
||||
have a common sequence of initial arguments]. Otherwise, our scheme above
|
||||
will not work.
|
||||
|
||||
The following illustrates an alternate scheme for manually wrapping an
|
||||
overloaded member function instead of
|
||||
[^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS]. Obviously, the same technique
|
||||
can be applied to wrapping overloaded non- member functions.
|
||||
|
||||
We have here our C++ classes:
|
||||
|
||||
struct X
|
||||
{
|
||||
bool f(int a, double b = 0, char c = 'x')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int f(int a, int b, int c)
|
||||
{
|
||||
return a + b + c;
|
||||
};
|
||||
};
|
||||
|
||||
Notice that class X has two overloaded functions with different signatures.
|
||||
The types of the arguments, and the return are totally different, unlike
|
||||
above where we have a common sequence of initial arguments.
|
||||
|
||||
We shall start by introducing some member function pointer variables:
|
||||
|
||||
bool (X::*fx1)(int) = &X::f;
|
||||
bool (X::*fx2)(int, double) = &X::f;
|
||||
bool (X::*fx3)(int, double, char)= &X::f;
|
||||
int (X::*fx4)(int, int, int) = &X::f;
|
||||
|
||||
The first three member function pointers take care of the first X::f
|
||||
overload. The one with default arguments. The last member function pointer
|
||||
takes care of the second X::f overload.
|
||||
|
||||
With these in hand, we can proceed to define and wrap this for Python:
|
||||
|
||||
.def("f", fx1)
|
||||
.def("f", fx2)
|
||||
.def("f", fx3)
|
||||
.def("f", fx4)
|
||||
will not work. If this is not the case, we have to wrap our functions
|
||||
[@overloading.html manually].
|
||||
|
||||
Actually, we can mix and match manual wrapping of overloaded functions and
|
||||
automatic wrapping through [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] and
|
||||
its sister, [^BOOST_PYTHON_FUNCTION_OVERLOADS]. Since the first overload
|
||||
has default arguments, we can use [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS]
|
||||
to automatically wrap the first three of the [^def]s above and manually
|
||||
wrap just the last. Here's how we'll do this:
|
||||
its sister, [^BOOST_PYTHON_FUNCTION_OVERLOADS]. Following up on our example
|
||||
presented in the section [@overloading.html on overloading], since the
|
||||
first overload has default arguments, we can use
|
||||
[^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] to automatically wrap the first
|
||||
three of the [^def]s above and manually wrap just the last. Here's how
|
||||
we'll do this:
|
||||
|
||||
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(xf_overloads, f, 1, 4)
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Virtual Functions with Default Implementations</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="deriving_a_python_class.html">
|
||||
<link rel="next" href="class_operators_special_functions.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="theme/c%2B%2Bboost.gif">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Virtual Functions with Default Implementations</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="deriving_a_python_class.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="class_operators_special_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Recall that in the <a href="class_virtual_functions.html">
|
||||
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>
|
||||
<code><pre>
|
||||
<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=number>0</span><span class=special>;
|
||||
};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
had a pure virtual function <tt>f</tt>. If, however, its member function <tt>f</tt> was
|
||||
not declared as pure virtual:</p>
|
||||
<code><pre>
|
||||
<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=keyword>return </span><span class=number>0</span><span class=special>; }
|
||||
};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
and instead had a default implementation that returns <tt>0</tt>, as shown above,
|
||||
we need to add a forwarding function that calls the <tt>Base</tt> default virtual
|
||||
function <tt>f</tt> implementation:</p>
|
||||
<code><pre>
|
||||
<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=identifier>self</span><span class=special>(</span><span class=identifier>self_</span><span class=special>) {}
|
||||
</span><span class=keyword>int </span><span class=identifier>f</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=keyword>int </span><span class=identifier>default_f</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=identifier>ADDED</span><span class=special>***
|
||||
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>self</span><span class=special>;
|
||||
};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Then, Boost.Python needs to keep track of 1) the dispatch function <tt>f</tt> and
|
||||
2) the forwarding function to its default implementation <tt>default_f</tt>.
|
||||
There's a special <tt>def</tt> function for this purpose. Here's how it is
|
||||
applied to our example above:</p>
|
||||
<code><pre>
|
||||
<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=string>"Base"</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>Base</span><span class=special>::</span><span class=identifier>f</span><span class=special>, &</span><span class=identifier>BaseWrap</span><span class=special>::</span><span class=identifier>default_f</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Note that we are allowing <tt>Base</tt> objects to be instantiated this time,
|
||||
unlike before where we specifically defined the <tt>class_<Base></tt> with
|
||||
<tt>no_init</tt>.</p>
|
||||
<p>
|
||||
In Python, the results would be as expected:</p>
|
||||
<code><pre>
|
||||
<span class=special>>>> </span><span class=identifier>base </span><span class=special>= </span><span class=identifier>Base</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=identifier>def </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>self</span><span class=special>):
|
||||
... </span><span class=keyword>return </span><span class=number>42
|
||||
</span><span class=special>...
|
||||
>>> </span><span class=identifier>derived </span><span class=special>= </span><span class=identifier>Derived</span><span class=special>()
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Calling <tt>base.f()</tt>:</p>
|
||||
<code><pre>
|
||||
<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></code>
|
||||
<p>
|
||||
Calling <tt>derived.f()</tt>:</p>
|
||||
<code><pre>
|
||||
<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></code>
|
||||
<p>
|
||||
Calling <tt>call_f</tt>, passing in a <tt>base</tt> object:</p>
|
||||
<code><pre>
|
||||
<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></pre></code>
|
||||
<p>
|
||||
Calling <tt>call_f</tt>, passing in a <tt>derived</tt> object:</p>
|
||||
<code><pre>
|
||||
<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></pre></code>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="deriving_a_python_class.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="class_operators_special_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -60,6 +60,16 @@
|
||||
<a href="doc/class_virtual_functions.html">Class Virtual Functions</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/deriving_a_python_class.html">Deriving a Python Class</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/virtual_functions_with_default_implementations.html">Virtual Functions with Default Implementations</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/class_operators_special_functions.html">Class Operators/Special Functions</a>
|
||||
@@ -75,6 +85,11 @@
|
||||
<a href="doc/call_policies.html">Call Policies</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/overloading.html">Overloading</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/default_arguments.html">Default Arguments</a>
|
||||
@@ -82,7 +97,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/overloading.html">Overloading</a>
|
||||
<a href="doc/auto_overloading.html">Auto-Overloading</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user