First publication date : 2021/04/28
We will go back to the example of the lesson : the modeling of shapes (Shape, Rectangle, Circle and Point) and the relationships between classes.
- Download the zip containing skeleton files
- Unzip the file
- Compile it by typing
makeon the command line - You can also compile it with
g++ -o exe *.cppbut you need to be patient each time you compile - Run the test program, type
./exe
To keep the things as simple as possible, all the classes will be declared in one sigle file (Shapes.hpp) and the corresponding implementation code will be in Shape.cpp. tests.cpp contains all the tests (not so many) we want to run. main_tests.cpp generates the main() function for the tests ; the catch library creates it.
Point
A class to represent a point with 2 integer coordinates x and y:
| Point |
| - x : integer - y : integer |
| + Point() + Point(x, y) + setX(x : integer) + getX() : integer + setY(y : integer) + getY() : integer |
With the catch library, here are the tests:
TEST_CASE("Point1") {
Point p;
CHECK( 0 == p.getX());
CHECK( 0 == p.getY());
}
TEST_CASE("Point2") {
Point p { 3, 2 };
//Point p (3,2);
CHECK( 3 == p.getX());
CHECK( 2 == p.getY());
}
TEST_CASE("Point3") {
Point p;
p.setX(6);
p.setY(7);
CHECK( 6 == p.getX());
CHECK( 7 == p.getY());
}
- Add the attributes (x and y)
- Add the
getmethods for both of them - Add the constructors (default and with parameter) to properly initialize the attributes. You can use the constructor delegation if you want to.
- Compile and run with "Point1", "Point2" and "Point3" tests, it should work !
Rectangle
A class to represent the basic shape given by a corner point, a width and a height as follows:
| Rectangle |
| - point : Point - width : integer - height : integer |
| + Rectangle() + Rectangle(x: integer, y: integer, w: integer, h: integer) + Rectangle(p: Point , w: integer, h: integer) + Shape(p : Point) + setPoint(p : Point) + getPoint() : Point + getWidth() : integer + getHeight() : integer + toString() : string |
The relationship between Point and Rectangle is a composition.
With the catch library, here is a basic test:
TEST_CASE("Rectangle1") {
Rectangle r;
CHECK( 0 == r.getPoint().getX());
CHECK( 0 == r.getPoint().getY());
CHECK( 0 == r.getWidth());
CHECK( 0 == r.getHeight());
}
- Add the attributes (point, width and height)
- Add the
getmethods for all of them - Add the constructors
- Compile and run the "Rectangle1" test, it should work !
The "Rectangle2" test is not working because, right now, we did not implement the inheritance relationship between Rectangle and Shape.
Shape
A class to represent any shape with a known bounding box (a rectangle) :
| Shape |
| - p : Point - width : integer - height : integer |
| + Shape() + Shape(x: integer, y: integer, w: integer, h: integer) + Shape(p : Point) + setPoint(p : Point) + getPoint() : Point + getWidth() : integer + getHeight() : integer + toString() : string |
This class aims to be abstract, that is why we will not write direct specific tests.
To make the following test working,
TEST_CASE("Rectangle2") {
// Rectangle is a Shape
Shape *s = new Rectangle;
CHECK( 0 == s->getPoint().getX());
CHECK( 0 == s->getPoint().getY());
CHECK( 0 == s->getWidth());
CHECK( 0 == s->getHeight());
}
- Rename the
Rectangleclass toShape - Create a new class
Rectangleclass stating that aRectangleIS aShape - Just add the correct constructors and that's it !
For the last test of the Rectangle class, there is more work to do :
TEST_CASE("Rectangle3") {
// Rectangle is a Shape
Shape *s = new Rectangle;
CHECK( "Rectangle" == s->toString());
}
- Add the
toString()method to theShapeclass. It can beabstractor just returning "Shape" for example. - Override the method in the
Rectangleclass
Circle
A class to represent a particular shape : the circle. The center and the radius are deduced from the bounding box.
The partial UML is as follows:
| Circle IS a Shape |
| radius ? center ? |
| + Circle() + Circle(x: integer, y: integer, w: integer, h: integer) + Circle(center : Point, radius: integer) + getRadius() : integer + toString() : string |
With the catch library, here are the tests:
TEST_CASE("Circle1") {
Circle c;
CHECK( 0 == c.getPoint().getX());
CHECK( 0 == c.getPoint().getY());
CHECK( 0 == c.getRadius());
CHECK( 0 == c.getWidth());
CHECK( 0 == c.getHeight());
}
TEST_CASE("Circle2") {
Circle c(Point(10,10),2);
CHECK( 8 == c.getPoint().getX());
CHECK( 8 == c.getPoint().getY());
CHECK( 2 == c.getRadius());
CHECK( 4 == c.getWidth());
CHECK( 4 == c.getHeight());
}
The Circle class is a Shape class, so we have to check the relationship:
TEST_CASE("Circle3") {
// Rectangle is a Shape
Shape *s = new Circle;
CHECK( "Circle" == s->toString());
}


