[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