Re: Mapping C++ classes onto Python classes?

Mark Lutz (mlutz@KaPRE.COM)
Fri, 30 Sep 1994 11:49:54 +0700

> I thought this would be a FAQ, but I found nothing on that topic:
> has anyone tried to extend Python by presenting an existing C++ class as a
> Python class? Are there any incompatibilities? If it works, did someone
> write a program to automatically generate the code that does the job?

It can be done a number of ways. Perhaps the most straightforward
way is to:

- wrap the C++ methods (and new/delete operations) in
'extern "C"' functions;

- make a Python C-extension modules that exports the C
wrappers to Python;

- define a stub class in Python to serve as the interface
to the C extension module functions.

Here's an extremely simple example:

(1) The C++ class (the one you want to use in Python):

class Simple {
public:
void show(char *message) { cout << message }
}

(2) The C-compatible wrapper functions (coded in C++):

#include <Simple.h>
extern "C" Simple * new_Simple()
{ return new Simple; }
extern "C" void del_Simple(Simple *obj)
{ delete obj; }
extern "C" void show_Simple(Simple *obj, char *message)
{ obj->show(message); }


(3) The C extension module (only the new/show parts are shown here)

extern char *new_Simple(); // defeat C++ type checking
extern void show_Simple(char *obj, char *msg)

static object *import_new_Simple(object *self, object *args)
{
char *obj = new_Printer(); // a char* in C
return mkvalue("i", obj); // an int in python
}

static object *import_show_Simple(object *self, object *args)
{
char *obj, *msg;
if (!getargs(args, "(is)", &obj, &msg))
return NULL;
show_Simple(obj, msg); // call C++ method for 'obj'
INCREF(None);
return None;
}

static struct methodlist Simple_methods[] = {
{"new_Simple", import_new_Simple},
{"show_Simple", import_show_Simple}, ...

// the usual 'methodlist' name/function table and init_Simple()
// start-up function; see Python extension manuals for details


(4) The Python stub class module: Simple.py

from _Simple import *

class Simple:
def __init__(self):
self._base = new_Simple() # store C++ superclass obj
def __del__(self):
del_Simple(self._base)
def show(self, message):
show_Simple(self._base, message)


(5) The Python client code:

from Simple import Simple
x = Simple()
x.show('Hello world!') # call the C++ method...
x = 0 (or del x) # calls __del__

A few notes:

- Part 3 is a normal C extension module, with static wrapper functions
that call the extern C++ wrappers, after converting Python arguments
to C form (getargs). Passes the C++ class instance to Python as an int
object, extract it as an int later.

- This is a really simple example, but scales up; for instance, to add
return types from C++ methods, you just add mkvalue() calls in the
C extension module wrappers. Similarly, C++ constructors can get
arguments,...

- It's not generally possible to support all of C++'s functionality
in Python. But you can at least handle new, delete, and method calls.
C++'s "esoteric" fetaures are harder; for instance, templates, operator
and function overloading, etc., is hard across language boundaries.

- If you want to support C++ virtual functions, there's more work to be
done: one solution is to define a C++ stub subclass, with definitions
for the virtuals which call back to the Python system (call_object, etc.)

- You can also export Python classes to C++; this is a bit harder, so
I won't go into it here...

Although I don't like to discuss work-in-progress until it's finished,
I'm working on a system that automatically generates all the code above
(and also handles simpler function-level integration). Basically, you
define your language integrations in a interface-description-language
that's 'compiled' into the appropriate code (which you then compile with
C and/or C++ compilers-- which gets around C++'s name-mangling). It's
not all that hard to do, and I'd be surprised if someone else isn't
doing something similar. More details as they emerge...

Hope this helps.

Mark Lutz