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
make
on the command line - You can also compile it with
g++ -o exe *.cpp
but 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
get
methods 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
get
methods 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
Rectangle
class toShape
- Create a new class
Rectangle
class stating that aRectangle
IS 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 theShape
class. It can beabstract
or just returning "Shape" for example. - Override the method in the
Rectangle
class
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());
}