First publication date : 2020/04/06
Object Oriented Programming : cooking
Can you create the Recipe class to make this piece of code working ?
#include <iostream>
class Recipe {
// work to do
};
int main(int, char**) {
Recipe cake;
cake.display();
// Here is the display :
// nothing to prepare
cake.setEggs(4); // number of eaggs
cake.setButter(240); // weight
cake.setFlour(240);
cake.setSugar(240);
cake.display();
// Here here the display :
// Eggs : 4, Flour : 240, …
cake.bake(180, 40); // temperature, time
cake.display();
// Here here the display :
// Recipe is ready to eat
}
To give you a hint :
| Recipe |
| - eggs : real - butter : real - flour : real - sugar : real |
| + constructor ? + setEggs(e: int) + setButter(b: real) + setFlour(f: real) + setSugar(s: real) + display() + bake(temp: integer, time: integer) |
The display() method has a different behavior depending on actions on the object. How can you model that, here is a solution if you need it ...
An easy way to model the behavior is to add anoter data member called state. For example, if state is equals to 0, it means that no information on content was given. If state is equals to 1, it means at least one information is given. If state is equals to 2, it means that the cake is cooked whatever the result is :-)
If you need more, I hide a piece of code :
class Recipe {
public:
Recipe() {
state = 0;
eggs = 0;
flour = .0;
}
void setEggs(int e) {
eggs = e;
state = 1;
}
void setFlour(double f) {
flour = f;
state = 1;
}
void bake(int, int) {
state = 2;
}
void display() {
if (state==0)
std:cout << "Nothing to do" << std::endl;
else if (state==1) {
std::cout << "Eggs:" << eggs << std::end;
std::cout << "Flour:" << flour << std::end;
}
else if (state==2)
std::cout << "Ready to eat ..." << std::endl;
}
private:
int state:
int eggs;
double flour;
};
Here we will see how a class data member works !!!
Introduction to Object Oriented Programming, from lecture to practical
The goal of this exercice is to implement and to instanciate a Point class with some data members while ensuring encapsulation.
| Point |
| - x : real - y : real |
| + Point() + Point(x, y) + setX(x : real) + getX() : real + setY(y : real) + getY() : real + moveTo(x, y) + moveFrom(dx, dy) |
Course examples are given as a reminder.
Your work has to be split into 2 or 3 files :
- a header file
Point.hppthat contains the declaration of the class - a code file
Point.cppthat contains the definition/implementation of the class - It is mandatory to have a
main()function in another filemain.cppor, at the pinch,Point.cpp
The skeleton to use is the following :
// Point.hpp file
// Watchers are missing, you have to add them
// Similar to C language
class Point {
// By default, all is private in a "class"
int x;
public:
int getX();
};
A header file as Point.hpp should never be compiled ! If you do so, you will have a "precompiled" header ! Delete this particular header if you do not know what you are doing.
Here are the implementation file of the class Point :
// File Point.cpp
#include <iostream> // To include a standard file
#include "Point.hpp" // To include a file from the current working directory
int Point::getX() {
return x;
}
You find now the entry point in main.cpp . Have a look at the #include with the quotation marks :
// File main.cpp
int main(int, char**) {
Point p;
std::cout << p.getX();
return 0;
}
#include "file" allows to include a file from the current/working directory.
#include <file> allows to include a file from a standard foler (usually /usr/[local]/include OR from a path given by the compiler option -I (uppercase i)
- Compile and run the program. What can we notice about the data members ?
Initialization is not automatic ! It depends on the compiler. Valgrind will help for that
- Add the
setX()(with the proper prototype) in the header file and in the implementation file. Check that calling the method inmain()changes the value ofxattribute - Remove the semicolon at the end of the class and try to compile. My compiler displays several errors and among them : (perhaps a semicolon is missing after the definition of ‘Point’)
- Add the
yattribute and the methodsmoveTo()andmoveFrom() - Check that the methods do what they really meant to.
Let's continue:
- Add two constructors, one with no argument and the other one with. The constructors have to write on the standard output their name (prototype) when they are called.
- Instanciate several objects of
Pointby calling the different constructors. - Instanciate also an object with the
newoperator - Add a class member named
counterwith the proper accessors. - Check that this attribute is properly defined before any object creation the check that the value is incremented when required
- Check the different ways to call the accessor (class and object)
- Check that this is not possible to access
xoryattributes in a class method (the opposite is possible) - Check that this is not possible to access a private member (class or instance) from outside the class
There is another way to define a class : you can use the struct keyword . All members (methods or data) are public instead of private with the class keyword.
Diaper ...
The following exercices aim at emphasizing some situations to avoid.
Gossip : different kinds of allocation
Complete the code of theGossip class with a constructor and a destructor
that display respectively "contruction of %" et "destruction of %" where % is a parameter given at the construction
(with a default value of 0).
#include <iostream>
class Gossip {
//
// Put you code in here
//
} weird(1);
Gossip global(2);
void dummy(Gossip g) {
std::cout << "dummy function code";
}
int main(int, char **) {
Gossip g;
Gossip * p = new Gossip(3);
// dummy(b);
return 0;
}
If you put the given code in separate files (as you should do for header and implementation) , be careful to the definitions of weird and global.
If the notion of destructor is unclear at this time, you just need to known that it is a special method called when the object is detroyed. Its definition may look like :
~Gossip() {
std::cout << "Destruction " << n << std::endl;
}
- What is
weird? - After checking the running code with
valgrind, what do you need to do ?
Maybe, you have to loock after *p.
- Uncomment le line 18. Why can we see more destructions than constructions ?
An instance is destroyed without its construction is displayed. There should be an implicit construction somewhere. We will see it in class : parameters in C++ are passed by value (copy) as in C language.
- Add a method that returns the parameter given at the construction (called a getter).
- Insert this code in the
main()function. What can you deduce about the lifespan of the object ?
int main(int, char **) {
std::cout << Gossip(0).get() << std::endl;
}
Gossiping arrays
Add a display() method that displays on the standard output "Display of %" and run the following code :
int main(int, char **) {
const int SIZE = 20;
Gossip arr1[SIZE];
Gossip * arr2 = new Gossip[SIZE];
for (int i =0; i < SIZE; ++i)
{
arr1[i].display();
arr2[i].display();
}
return 0;
}
Of course, the allocated memory to arr2 is not freed...You have to do it with the proper version of delete.
You have to notice that instances have been made when the arrays were created.
A complex object : a pair
Write a Pair class that have two objects of type Gossip as data members.
- Instanciate and check that 3 objects are indeed created and the destroyed (valgrind ...)
- Use an initialization list to give distinct values for
Gossipinstances - Check that desallocations are made in the reverse order of allocations.
- The attributes have to be initialized in the order of declaration. Try to reorder them to discover the warning/error message.
The option -Wreorder produces a message, it is included in -Wall
A complex object : a big family
- Write a class
Familythat defines a pointer to handle an array ofGossipelements - Add a constructor that allocates an array whose size is given (a parameter). The value 0 is acceptable.
- Test a program that instanciates one or more
Familyobjects with valgrind and notice what is going on. - Add the proper destructor
malloc/free vs new/delete
Instantiate an object of Gossip class with malloc(). Display the "value" field of the obect. What is happening ? (to compare with the use of new)
Run valgrind !!!
To include a C header file (malloc() and free() are defined in stdlib.h), it is easy, you have to prefix the library name with the -c- and to forget the extension :
#include <cstdlib>
Makefile
You will find a example of makefile file with automatic dependancies generation. It uses the -MMD option of the C++ compiler. Dependancies files (*.d) and objects files (*.o) are created in a disposable folder called build.
You have to run the command make to do the magic.
If you copy the following code, pay attention to the fact the lines begin with tabulations and not spaces !
SRC=main.cpp obj.cpp
#SRC=$(wildcard *.cpp)
EXE=exe_name
CXXFLAGS+=-Wall -Wextra -MMD -g -O2 -fdiagnostics-color=auto
LDFLAGS= #-lSDL
OBJ=$(addprefix build/,$(SRC:.cpp=.o))
DEP=$(addprefix build/,$(SRC:.cpp=.d))
all: $(OBJ)
$(CXX) -o $(EXE) $^ $(LDFLAGS)
build/%.o: %.cpp
@mkdir -p build
$(CXX) $(CXXFLAGS) -o $@ -c $<
clean:
rm -rf build core *.gch
-include $(DEP)
An @ deactivates the display of the line (=> no standard output).
The include command allows including other makefiles like makefile.dep. If the included file do not exist, error is ignored if the "-" prefix is given .
This makefile erases the precompiled headers if they exist (clean rule).
To conclude, if your are compiling on a more than one processor or core and if the command takes time, you can use the machine architecture by activating the -j n flag where n is the number of processors/cores that you want to use to compile.
You want more ? Read the manual !!!
The red string...gesture
We will do a project that is called in french "fil rouge" or "red string" if you translate it literally. This project will be used to go through notions you have seen in previous practical works and thay will have to fit together for a bigger work
The objective is to design a program that handles vectorial shapes in text mode :-(
We will handle shapes like rectangles or circles.
Create a Rectangle class with the following attributes : coordinates x and y , a width w and a height h. All the values are integer. Write a constructor that initializes all the parameters. We will later model the coordinates as a Point
| Rectangle |
| - x : integer - y : integer - w : integer - h : integer |
| + Rectangle(x, y, w, h) + toString() : string |
Create a Circle class with the same attributes than the Rectangle class. We will consider that a circle is bounds by a rectangle. You will add another constructor to define a circle knowning its center and radius.
| Circle |
| - x : integer - y : integer - w : integer - h : integer |
| + Circle(x, y, w, h) + Circle(x, y , rayon) + toString() : string |
The toString() method returns a character string (std::string) that gives a text representation. Here is a possible output :
CIRCLE 10 10 30 30
RECTANGLE 30 30 15 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10



