2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-21 17:12:22 +00:00
Files
python/overriding.html
Dave Abrahams 1088183bae Release 2000-11-06
[SVN r8151]
2000-11-06 05:24:07 +00:00

195 lines
6.7 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Overridable Virtual Functions</title>
<img src="c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
width="277" height="86">
<h1>Overridable Virtual Functions</h1>
<p>
In the <a href="example1.html">previous example</a> we exposed a simple
C++ class in Python and showed that we could write a subclass. We even
redefined one of the functions in our derived class. Now we will learn
how to make the function <em>behave virtually</em>.
<h2><a name="overriding_example">Example</a></h2>
<p>In this example, it is assumed that <code>world::get()</code> is a virtual
member function:
<blockquote><pre>
class world
{
public:
   world(int);
    virtual ~world();
    <b>virtual</b> const char* get() const { return "hi, world"; }
};
</pre></blockquote>
<p>
We'll need a derived class<a href="#why_derived">*</a> to help us
dispatch the call to Python. In our derived class, we need the following
elements:
<ol>
<li><a name="derived_1">A</a> <code>PyObject*</code> data member that holds a reference to the
corresponding Python object.
<li><a name="derived_2">A</a> constructor for each exposed constructor of the base class which stores an
additional initial <code>PyObject*</code> argument in the data
member described above.
<li><a name="derived_3">An</a> implementation of each virtual function you may wish to override in
Python which uses
<code>py::Callback&lt<i>return-type</i>&gt;::call_method()</code> to call the
Python override.
<li><a name="derived_4">For</a> each non-pure virtual function meant to be overridable from Python, a
static member function (or a free function) taking a reference or pointer to the
base type as the first parameter and which forwards any additional parameters
neccessary to the <i>default</i> implementation of the virtual function. See also
<a href="#private">this note</a> if the base class virtual function is private.
</ol>
<blockquote><pre>
struct world_callback : world
{
world_callback(PyObject* self, int x) // <a href="#derived_2">2</a>
: world(x),
m_self(self) {}
const char* get() const // <a href="#derived_3">3</a>
{ return py::Callback&lt;const char*&gt;::call_method(m_self, "get"); }
static const char* <a name= "default_implementation">default_get</a>(const hello::world& self) const // <a href="#derived_4">4</a>
{ return self.world::get(); }
private:
PyObject* m_self; // <a href="#derived_1">1</a>
};
</pre></blockquote>
<p>
Finally, we add <code>world_callback</code> to the <code>
ClassWrapper&lt;&gt;</code> declaration in our module initialization
function, and when we define the function, we must tell py_cpp about the default
implementation:
<blockquote><pre>
// Create the <a name=
"world_class">Python type object</a> for our extension class
py::ClassWrapper&lt;hello::world<strong>,world_callback&gt;</strong> world_class(hello, "world");
// Add a virtual member function
world_class.def(&amp;world::get, "get", &amp;<b>world_callback::default_get</b>);
</pre></blockquote>
<p>
Now our subclass of <code>hello.world</code> behaves as expected:
<blockquote><pre>
&gt;&gt;&gt; class my_subclass(hello.world):
... def get(self):
... return 'hello, world'
...
&gt;&gt;&gt; hello.length(my_subclass())
12
</pre></blockquote>
<p>
<a name="why_derived">*</a>You may ask, "Why do we need this derived
class? This could have been designed so that everything gets done right
inside of <code>hello::world</code>." One of the goals of py_cpp is to be
minimally intrusive on an existing C++ design. In principle, it should be
possible to expose the interface for a 3rd party library without changing
it. To unintrusively hook into the virtual functions so that a Python
override may be called, we must use a derived class.
<h2>Pure Virtual Functions</h2>
<p>
A pure virtual function with no implementation is actually a lot easier
to deal with than a virtual function with a default implementation. First
of all, you obviously don't need to <a href="#default_implementation">
supply a default implementation</a>. Secondly, you don't need to call
<code>def()</code> on the <code>ExtensionClass&lt;&gt;</code> instance
for the virtual function. In fact, you wouldn't <em>want</em> to: if the
corresponding attribute on the Python class stays undefined, you'll get
an <code>AttributeError</code> in Python when you try to call the
function, indicating that it should have been implemented. For example:
<blockquote>
<pre>
struct baz {
<strong>virtual</strong> int pure(int) = 0;
};
struct baz_callback {
int pure(int x) { py::Callback&lt;int&gt;::call_method(m_self, "pure", x); }
};
extern "C"
#ifdef _WIN32
__declspec(dllexport)
#endif
initfoobar()
{
try
{
py::Module foobar("foobar");
py::ClassWrapper&lt;baz,baz_callback&gt; baz_class("baz");
baz_class.def(&amp;baz::pure, "pure");
}
catch(...)
{
py::handle_exception(); // Deal with the exception for Python
}
}
</pre>
</blockquote>
<p>
Now in Python:
<blockquote>
<pre>
&gt;&gt;&gt; from foobar import baz
&gt;&gt;&gt; x = baz()
&gt;&gt;&gt; x.pure(1)
Traceback (innermost last):
File "&lt;stdin&gt;", line 1, in ?
AttributeError: pure
&gt;&gt;&gt; class mumble(baz):
... def pure(self, x): return x + 1
...
&gt;&gt;&gt; y = mumble()
&gt;&gt;&gt; y.pure(99)
100
</pre></blockquote>
<a name="private"><h2>Private Non-Pure Virtual Functions</h2></a>
<p>This is one area where some minor intrusiveness on the wrapped library is
required. Once it has been overridden, the only way to call the base class
implementation of a private virtual function is to make the derived class a
friend of the base class. You didn't hear it from me, but most C++
implementations will allow you to change the declaration of the base class in
this limited way without breaking binary compatibility (though it will certainly
break the <a
href="http://cs.calvin.edu/c++/C++Standard-Nov97/basic.html#basic.def.odr">ODR</a>).
<p>
Prev: <a href="example1.html">A Simple Example Using py_cpp</a> Next: <a
href="overloading.html">Function Overloading</a> Up: <a href=
"py_cpp.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. 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.
<p>
Updated: Oct 30, 2000