summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Bradshaw <robertwb@gmail.com>2016-03-24 21:47:26 -0700
committerRobert Bradshaw <robertwb@gmail.com>2016-03-24 21:56:08 -0700
commit375346353992038cba28bd596964fe7d3ff4457d (patch)
tree02a47c79bf15f776e78518bebdbb9c6f3753b6dd
parentcb0e2dc3f618b2f4d97bd73e8542f245aeb8fd64 (diff)
downloadcython-robertwb-rect.tar.gz
Update C++ Rectangle example.robertwb-rect
-rw-r--r--docs/src/userguide/wrapping_CPlusPlus.rst77
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>`.