[Pyrex] A Quick Guide to C++ in Pyrex
Lenard Lindstrom
len-l at telus.net
Thu Apr 13 02:19:51 CEST 2006
I hope this helps new users of Pyrex with C++ by bringing together in
one posting various points scattered throughout other messages.
The Pyrex language has no builtin support for C++. Luckily existing
language features can persuade Pyrex to write C++ code. A Pyrex
module can wrap externally declared C++ classes as extension types.
The following sections use this example C++ include file code:
// klass.h
class SomeClass
{
public:
SomeClass();
~SomeClass();
int method_a(int a);
};
class Derived : public SomeClass
{
public:
void method_b ();
int method_c(int n);
double method_c(double x);
};
namespace cpp
{
extern double y;
}
Declaring an External C++ class:
Syntactically C++ classes act like typedef'd C structures. So use
ctypedef in the cdef extern from statement.
cdef extern from "klass.h":
ctypedef struct SomeClass:
...
Declaring C++ methods:
Method calls resemble function pointer calls. So declare methods as
function pointer fields of the class. Do not include constructor and
destructor methods.
ctypedef struct SomeClass:
int (* method_a)(int a)
Declaring a Class Constructor:
Class instances can be created dynamically using C++ new. An
allocator can be declared using a Pyrex C name specifier. The
allocator is a function that takes the arguments of the class
constructor and returns a pointer to a class instance.
SomeClass *someclass_factory "new SomeClass" ()
The allocator is called like any other function:
cdef SomeClass *s
s = someclass_factory()
Declaring a Universal Deallocator:
Unlike allocators, a single delete function can handle all class
types.
void delete "delete " (void *o)
It is also called as a function:
delete(s)
Subclasses:
Any methods of the parent class that will be called in the Pyrex
module must be redeclared for the subclass. The subclass also needs
its own constructor function.
ctypedef struct Derived:
int (* method_a)(int a)
void (* method_b)()
...
Derived *derived_factory "new Derived" ()
Overloaded methods:
Give each overloaded function its own Pyrex name. Use a C name
specifier for its C++ name. This also applies to overloaded
functions.
ctypedef struct Derived:
...
int (* method_c_int "method_c") (int n)
double (* method_c_double "method_c") (double x)
Name Spaces:
Again the Pyrex C name specifier comes to the rescue. Provide the
fully qualified name in the specifier:
double y "cpp::y"
Wrapping a C++ Class With an Extension Type:
Only keep pointers to C++ class instances with an extension type. C++
constructors and destructors will not get called otherwise. Use Pyrex
special methods __new__ and __dealloc__ to create and destroy C++
class instances.
cdef class PySomeClass:
cdef SomeClass *thisptr
def __new__(self):
self.thisptr = someclass_factory()
def __dealloc__(self):
delete(self.thisptr)
def method_a(self, int a):
return self.thisptr[0].method_a(a)
Extension type inheritance will not work as a shortcut for declaring
a wrapper for a derived C++ class. Treat each C++ class as if it has
no base class.
Other Matters:
Pyrex C name specifiers also handle overloaded C++ operators. Pyrex
cannot catch C++ exceptions. These will continue to unwind the C
stack and crash the Python interpreter. C++ wrappers are needed.
Templates are an open issue.
Lenard Lindstrom
<len-l at telus.net>
More information about the Pyrex
mailing list