diff options
author | Robert Bradshaw <robertwb@gmail.com> | 2016-03-24 21:47:26 -0700 |
---|---|---|
committer | Robert Bradshaw <robertwb@gmail.com> | 2016-03-24 21:56:08 -0700 |
commit | 375346353992038cba28bd596964fe7d3ff4457d (patch) | |
tree | 02a47c79bf15f776e78518bebdbb9c6f3753b6dd | |
parent | cb0e2dc3f618b2f4d97bd73e8542f245aeb8fd64 (diff) | |
download | cython-robertwb-rect.tar.gz |
Update C++ Rectangle example.robertwb-rect
-rw-r--r-- | docs/src/userguide/wrapping_CPlusPlus.rst | 77 |
1 files changed, 48 insertions, 29 deletions
diff --git a/docs/src/userguide/wrapping_CPlusPlus.rst b/docs/src/userguide/wrapping_CPlusPlus.rst index a23cc5a2e..6b954a970 100644 --- a/docs/src/userguide/wrapping_CPlusPlus.rst +++ b/docs/src/userguide/wrapping_CPlusPlus.rst @@ -48,11 +48,11 @@ document. Let's assume it will be in a header file called class Rectangle { public: int x0, y0, x1, y1; + Rectangle(); Rectangle(int x0, int y0, int x1, int y1); ~Rectangle(); - int getLength(); - int getHeight(); int getArea(); + void getSize(int* width, int* height) void move(int dx, int dy); }; } @@ -65,6 +65,8 @@ and the implementation in the file called :file:`Rectangle.cpp`: namespace shapes { + Rectangle::Rectangle() { } + Rectangle::Rectangle(int X0, int Y0, int X1, int Y1) { x0 = X0; y0 = Y0; @@ -74,18 +76,15 @@ and the implementation in the file called :file:`Rectangle.cpp`: Rectangle::~Rectangle() { } - int Rectangle::getLength() { - return (x1 - x0); - } - - int Rectangle::getHeight() { - return (y1 - y0); - } - int Rectangle::getArea() { return (x1 - x0) * (y1 - y0); } + void Rectangle::getSize(int *width, int *height) { + width = x1 - x0; + height = y1 - y0; + } + void Rectangle::move(int dx, int dy) { x0 += dx; y0 += dy; @@ -192,11 +191,11 @@ We now need to declare the attributes and methods for use on Cython:: cdef extern from "Rectangle.h" namespace "shapes": cdef cppclass Rectangle: + Rectangle() except + Rectangle(int, int, int, int) except + int x0, y0, x1, y1 - int getLength() - int getHeight() int getArea() + void getSize(int* width, int* height) void move(int, int) Note that the constructor is declared as "except +". If the C++ code or @@ -229,7 +228,7 @@ a "default" constructor:: ... Note that, like C++, if the class has only one constructor and it -is a default one, it's not necessary to declare it. +is a nullary one, it's not necessary to declare it. Create Cython wrapper class ---------------------------- @@ -239,33 +238,53 @@ of the C++ Rectangle type. Now, we need to make this accessible from external Python code (which is our whole point). Common programming practice is to create a Cython extension type which -holds a C++ instance pointer as an attribute ``thisptr``, and create a bunch of +holds a C++ instance as an attribute and create a bunch of forwarding methods. So we can implement the Python extension type as:: cdef class PyRectangle: - cdef Rectangle *thisptr # hold a C++ instance which we're wrapping + cdef Rectangle c_rect # hold a C++ instance which we're wrapping def __cinit__(self, int x0, int y0, int x1, int y1): - self.thisptr = new Rectangle(x0, y0, x1, y1) - def __dealloc__(self): - del self.thisptr - def getLength(self): - return self.thisptr.getLength() - def getHeight(self): - return self.thisptr.getHeight() - def getArea(self): - return self.thisptr.getArea() + self.c_rect = Rectangle(x0, y0, x1, y1) + def get_area(self): + return self.c_rect.getArea() + def get_size(self) + int width, int height + self.c_rect.getSize(&width, &height) + return width, height def move(self, dx, dy): - self.thisptr.move(dx, dy) + self.c_rect.move(dx, dy) And there we have it. From a Python perspective, this extension type will look -and feel just like a natively defined Rectangle class. If you want to give +and feel just like a natively defined Rectangle class. +It should be noted that + +If you want to give attribute access, you could just implement some properties:: - property x0: - def __get__(self): return self.thisptr.x0 - def __set__(self, x0): self.thisptr.x0 = x0 + @property + def x0(self): + return self.c_rect.x0 + + @x0.setter + def x0(self): + def __set__(self, x0): self.c_rect.x0 = x0 ... +Cython initializes C++ class attributes of a cdef class using the nullary constructor. +If the class you're wrapping does not have a nullary constructor, you must store a pointer +to the wrapped class and manually allocate and deallocate it. +A convienient and safe place to do so is in the `__cinit__` and `__dealloc__` methods +which are guaranteed to be called exactly once upon creation and deletion of the Python +instance. + + cdef class PyRectangle: + cdef Rectangle* c_rect # hold a pointer to the C++ instance which we're wrapping + def __cinit__(self, int x0, int y0, int x1, int y1): + self.c_rect = new Rectangle(x0, y0, x1, y1) + def __dealloc__(self): + del self.c_rect + ... + If you prefer giving the same name to the wrapper as the C++ class, see the section on :ref:`resolving naming conflicts <resolve-conflicts>`. |