Copy of https://perso.isima.fr/loic/cpp/tp02.en.php
tete du loic

 Loïc YON [KIUX]

  • Enseignant-chercheur
  • Référent Formation Continue
  • Responsable des contrats pros ingénieur
  • Référent entrepreneuriat
  • Responsable de la filière F2 ingénieur
  • Secouriste Sauveteur du Travail
mail
loic.yon@isima.fr
phone
(+33 / 0) 4 73 40 50 42
location_on
Institut d'informatique ISIMA
  • twitter
  • linkedin
  • viadeo

[C++] PW 2

 This page might be outdated. Please email me if you found something incorrect.
Lire en Français

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 :

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)

Initialization is not automatic ! It depends on the compiler. Valgrind will help for that

Let's continue:

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;
}  

Maybe, you have to loock after *p.

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.

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.

The option -Wreorder produces a message, it is included in -Wall

A complex object : a big family

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