Copy of https://perso.isima.fr/loic/cpp/tp03.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 3

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

First publication date : 2020/04/16

Modeling exercise

To do this exercise, you need to read the note about the streams and the note about catch and unit tests. The program skeleton is provided with the lesson

The goal is to help a statistician that uses data from different sources (data producers).

The source file main.cpp what can happens with a demo.txt. The file is parsed and some "statistics" are computed...


Statistician s;
s.acquire("demo.txt");
std::cout << "Count: "  << s.getCount() << std::endl;
std::cout << "Sum:   "  << s.getSum()   << std::endl;
std::cout << "Mean:   " << s.getMean()  << std::endl;

With the catch library, you will write:

Each producer will have a produce() method to create the given file


bool produce(std::string name, int a, int b);

Each producer will be able to count the number of times the produce() method is called with an attribute work and the appropriate get method.


TEST_CASE("Producer_Initialization") {
  ConstantProducer p;
  REQUIRE( p.getWork() == 0);
}

TEST_CASE("Producer_work2") {
  ConstantProducer p;
  p.produce(10, "test01.txt");
  p.produce(10, "test01.txt");
  p.produce(10, "test01.txt");
  REQUIRE( p.getWork() == 3);
}

The test file for the Incremental Producer can looks like this:

TEST_CASE("Producer_Work3") {

    const int         DEMAND    = 10;
    const std::string FILE_NAME("test01.txt");
    int               reading, i;
    IncrementalProducer          p; 


    p.produce(DEMAND, FILE_NAME.c_str());

    std::ifstream file(FILE_NAME.c_str());

    REQUIRE(file.is_open());

    if (!file.eof()) {
      file >> reading; 
      REQUIRE(DEMAND == reading);
      for (i = 0; i < DEMAND; ++i) {
        file >> reading;
        REQUIRE( reading == (i+1) );
      }
    
    REQUIRE(i == DEMAND);
    // CHECK(file.eof());
    file.close();

    REQUIRE(p.getWork() == 1);
  }
}

We can add more tests. If you want to test your statistcian, do not forget that the sum of the n first integers is equals to n*(n+1)/2.

You can also write a Random Producer and add a menu to the application !!


Producer * p = new RandomProducer();
p->produce("file.txt", 30, -1);

Simple public inheritance

Illustration

An object of class Daughter IS before anything else an object of class Mother, that is why constructing a new Daughter object calls first the Mother constructor. We can see destructions are called in reverse way.

An object of Daughter class is by definition Mother object as well, that is why the constructor of the super class is called even if it is not officially mentioned. Do not forget it though, it kinda "comment" the code.

You need a class member attribute to do the trick (Mother class)!

The method is inherited : it is available in the daughter class even if it not defined.

The constructor with parameter from Mother class is not inherited. You need to give one (write it) in the Daughter class. C++11 allows to get all the constructors of the mother class.

Mother   *pm = new Mother("mere_dyn");
Daughter *pf = new Daughter("dynamic mother");
Mother   *pp = new Daughter("daughter seen as a mother");
pm->display(); // displays "Mother"
pf->display(); // displays "Daughter"
pp->display(); // displays "Daughter"

What about ...

What does the following program ?

class Mother {
  protected:
    string name;
  public: 
    Mother(string s="not provided"):name(s) {
    }
   
   void method1() {
       cout << "M1" << name << endl;
   }
};

class Daughter : public Mother {
  private:
    string name;
  public:
  
  Daughter():Mother("noname") {
  }

  void method2() {
      cout << "M2" << name << endl;
    }
};

int main(int, char**) {
   Daughter d;

   d.method1();
   d.method2();
}

You can copy-paste or type this code but you can also get it with git (question.cpp - not translated)

If you have already set up the gitenvironment, type the command :

git clone https://gitlab.com/kiux/CPP3.git

The name attribute of the Mother class is hidden in the Daughter class. To reach it again, you need to qualify it like this : Mother::name

Messages

This exercice is not difficult but it is mandatory to have the declaration and the implementation in two separate files. Give up if you spend more than 10 minutes on it.

Write two classes A and B. The class A declares a i integer attribute and the class B another one called j. Both classes have a method exec() and a method send() that allows to send data to the other class.

Running send() method calls an exec() method on a remote object with a constant of your choice. Thus oneA.send(&oneB) activates the send() method of a oneA object (class A) that calls the exec() method of object oneB (class B).

To do this, you need

B class needs A class and A class needs B class. There is a circle in the declarations. You have to use forward declarations to make it work. To do this, you have to restrict the use to references or pointers of other class objects. You cannot handle object that ar not entirely defined.

Red string...gesture

We will continue the application.

List
+ circles : array
+ nb_c : integer
+ rectangles : array
+ nb_r : integer
+ counter : integer
+ List()
+ getCounter() : integer
+ toString() : string

This way of doing is not handy nor efficient. We can of course do best but we will do it later on !