Skip to content
Snippets Groups Projects
Commit e7209d64ef2c authored by Robert Bradshaw's avatar Robert Bradshaw
Browse files

Update C++ Rectangle example.

parent 9bb933bd3aff
Branches robertwb-rect robertwb-rect_bookmark
No related tags found
No related merge requests found
...@@ -48,5 +48,6 @@ ...@@ -48,5 +48,6 @@
class Rectangle { class Rectangle {
public: public:
int x0, y0, x1, y1; int x0, y0, x1, y1;
Rectangle();
Rectangle(int x0, int y0, int x1, int y1); Rectangle(int x0, int y0, int x1, int y1);
~Rectangle(); ~Rectangle();
...@@ -51,5 +52,3 @@ ...@@ -51,5 +52,3 @@
Rectangle(int x0, int y0, int x1, int y1); Rectangle(int x0, int y0, int x1, int y1);
~Rectangle(); ~Rectangle();
int getLength();
int getHeight();
int getArea(); int getArea();
...@@ -55,4 +54,5 @@ ...@@ -55,4 +54,5 @@
int getArea(); int getArea();
void getSize(int* width, int* height)
void move(int dx, int dy); void move(int dx, int dy);
}; };
} }
...@@ -65,6 +65,8 @@ ...@@ -65,6 +65,8 @@
namespace shapes { namespace shapes {
Rectangle::Rectangle() { }
Rectangle::Rectangle(int X0, int Y0, int X1, int Y1) { Rectangle::Rectangle(int X0, int Y0, int X1, int Y1) {
x0 = X0; x0 = X0;
y0 = Y0; y0 = Y0;
...@@ -74,7 +76,7 @@ ...@@ -74,7 +76,7 @@
Rectangle::~Rectangle() { } Rectangle::~Rectangle() { }
int Rectangle::getLength() { int Rectangle::getArea() {
return (x1 - x0); return (x1 - x0) * (y1 - y0);
} }
...@@ -79,11 +81,8 @@ ...@@ -79,11 +81,8 @@
} }
int Rectangle::getHeight() { void Rectangle::getSize(int *width, int *height) {
return (y1 - y0); width = x1 - x0;
} height = y1 - y0;
int Rectangle::getArea() {
return (x1 - x0) * (y1 - y0);
} }
void Rectangle::move(int dx, int dy) { void Rectangle::move(int dx, int dy) {
...@@ -192,5 +191,6 @@ ...@@ -192,5 +191,6 @@
cdef extern from "Rectangle.h" namespace "shapes": cdef extern from "Rectangle.h" namespace "shapes":
cdef cppclass Rectangle: cdef cppclass Rectangle:
Rectangle() except +
Rectangle(int, int, int, int) except + Rectangle(int, int, int, int) except +
int x0, y0, x1, y1 int x0, y0, x1, y1
...@@ -195,5 +195,3 @@ ...@@ -195,5 +195,3 @@
Rectangle(int, int, int, int) except + Rectangle(int, int, int, int) except +
int x0, y0, x1, y1 int x0, y0, x1, y1
int getLength()
int getHeight()
int getArea() int getArea()
...@@ -199,4 +197,5 @@ ...@@ -199,4 +197,5 @@
int getArea() int getArea()
void getSize(int* width, int* height)
void move(int, int) void move(int, int)
Note that the constructor is declared as "except +". If the C++ code or Note that the constructor is declared as "except +". If the C++ code or
...@@ -229,7 +228,7 @@ ...@@ -229,7 +228,7 @@
... ...
Note that, like C++, if the class has only one constructor and it 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 Create Cython wrapper class
---------------------------- ----------------------------
...@@ -239,7 +238,7 @@ ...@@ -239,7 +238,7 @@
external Python code (which is our whole point). external Python code (which is our whole point).
Common programming practice is to create a Cython extension type which 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:: forwarding methods. So we can implement the Python extension type as::
cdef class PyRectangle: cdef class PyRectangle:
...@@ -243,5 +242,5 @@ ...@@ -243,5 +242,5 @@
forwarding methods. So we can implement the Python extension type as:: forwarding methods. So we can implement the Python extension type as::
cdef class PyRectangle: 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): def __cinit__(self, int x0, int y0, int x1, int y1):
...@@ -247,11 +246,9 @@ ...@@ -247,11 +246,9 @@
def __cinit__(self, int x0, int y0, int x1, int y1): def __cinit__(self, int x0, int y0, int x1, int y1):
self.thisptr = new Rectangle(x0, y0, x1, y1) self.c_rect = Rectangle(x0, y0, x1, y1)
def __dealloc__(self): def get_area(self):
del self.thisptr return self.c_rect.getArea()
def getLength(self): def get_size(self)
return self.thisptr.getLength() int width, int height
def getHeight(self): self.c_rect.getSize(&width, &height)
return self.thisptr.getHeight() return width, height
def getArea(self):
return self.thisptr.getArea()
def move(self, dx, dy): def move(self, dx, dy):
...@@ -257,4 +254,4 @@ ...@@ -257,4 +254,4 @@
def move(self, dx, dy): 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 there we have it. From a Python perspective, this extension type will look
...@@ -259,5 +256,8 @@ ...@@ -259,5 +256,8 @@
And there we have it. From a Python perspective, this extension type will look 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:: attribute access, you could just implement some properties::
...@@ -262,8 +262,27 @@ ...@@ -262,8 +262,27 @@
attribute access, you could just implement some properties:: attribute access, you could just implement some properties::
property x0: @property
def __get__(self): return self.thisptr.x0 def x0(self):
def __set__(self, x0): self.thisptr.x0 = x0 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 If you prefer giving the same name to the wrapper as the C++ class, see the
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment