Copy of https://perso.isima.fr/loic/cpp/tp06.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++] TP 6

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

First publication date: 2020/05/23

The canonical normal form

The following code whil helps us for analysing the behavior of the copy constructor and the assignment operator through inheritance and composition/aggregation. You can also reuse the code of the Gossip class.

class M {
 public:  
  M() {
    std::cout << "M::M()" << std::endl;
  }
   ~M() {
    std::cout << "M::~M()" << std::endl;
  }
    M(const M&) {
    std::cout << "M::M(const M&)" << std::endl;
  }
  
};

class D : public M {
 public:
  D() {
    std::cout << "D::D()" << std::endl;
  }  
~D() {
    std::cout << "D::~D()" << std::endl;
  }
  /*  
  D(const D& d) {
    std::cout << "D::D(const D&)" << std::endl;
  } 
  */
};

int main(int, char**) {

  D d1;
  D d2 = d1;
  
  d1 = d2;

  return 0;
}

Let us begin with the copy constructor

The default copy constructor from D calls the copy constructor of M.

The copy constructor from M is not called anymore : the default constructor is called .

You need to explicitly the copy constructor from M with the initilization list.

Let's consider now the assigment operator :

The default assignment operator of F calls this operator.

The assigment operator of class M is not called anymore !

If you have clicked here, you forgot what is written in the lesson with the contains() method of Shape, Circle and Rectangle. The syntax is the following: Mother_class_name::method(parameters)

It now the time to end with aggregation...

Exceptions

Add the exception mecanism to the classes of the last practical work, that is to know :

The exceptions we have to cope with are :

TEST_CASE("exceptions with bounds") {
  String s(10);
    
  REQUIRE_THROWS_AS( s[-1] == 0, String::OutOfRangeException);
  // OU
  REQUIRE_THROWS_AS( s[-1] == 0, std::out_of_range);
  REQUIRE_THROWS_AS( s[12] == 0, std::bad_alloc);  // :-)
}
TEST_CASE("exceptions with null pointer") {
  String s(0);
    
  // check that inheritance is done
  std::logic_error * pe = new null_pointer;  
  delete pe;

  REQUIRE_THROWS_AS( s[1] == 0, null_pointer);
}

To detect a bad allocation, you may initialize an array with an gigenormous siez or you can do a very LOOOOOOONNNNG loop.

Program ending

Run the program below. You will see the different behaviors when quitting the program :

class Gossip {
  std::string name;
 public :
   Gossip(std::string n):name(n) {
      std::cout << "constructor " << name << std::endl;
   }
   ~Gossip() {
      std::cout << "destructor " << name << std::endl;
   }
};

Gossip g("global");

int main(int, char **) {
   Gossip t("local");
   static Gossip s("statlocal");

   //std::exit(1);
   //std::terminate();
   //std::unexpected(); // you don't call it 
   return 0;
}

The Stack class

We will go on the study of containers with a stack of integers.

The first version will have a fixed size. The size will be choosen at initialization and an exception will emphasize the stack overflow.

You have to implement the following methods :

You will reuse this class in the TP on templates. You will find some tests :

TEST_CASE("default constructor") {
   Stack s; // implies that the default size is not null
   
   CHECK(  s.empty() );
   CHECK(  0 == s.size() );
}

TEST_CASE("Bad construction exception") {

   REQUIRE_THROWS_AS( Stack(-1).empty(), std::invalid_argument );
   REQUIRE_THROWS_AS( Stack( 0).empty(), std::invalid_argument );
   
}

TEST_CASE("Empty stack exception") {

   REQUIRE_THROWS_AS( Stack().pop(), std::invalid_argument );
   
}

TEST_CASE("living stack") {
    Stack s(10);

    CHECK(  s.empty() );
    CHECK(  0 == s.size() );

    s.push(5);

    CHECK( !s.empty() );
    CHECK( 1 == s.size() );
    CHECK( 5 == s.top() );

    s.push(2);
    s.push(1);

    CHECK( 3 == s.size() );
    CHECK( 1 == s.top() );

    s.pop();

    CHECK( 2 == s.size() );
    CHECK( 2 == s.top() );

    s.pop();
    s.pop();

    CHECK( 0 == s.size() );

}