Correction
Série Notée (Bonus)
Sujet 1
Note: 15 points sur 80 étaient facultatifs.
Exercice 1 : Bases de la POO, Héritage, Polymorphisme
Quelques remarques (suite à des erreurs/maladresses dans les copies):
- le concept d'héritage est encore parfois mal compris :
- certain définissent dans la super-classe les attributs prévus dans les sous-classes, d'autres redéfinissent dans les sous-classes des attributs déjà hérités des super-classes!
- si dans une classe, une méthode utilise un attribut, il ne faut pas lui passer l'attribut en paramètre. Les attributs d'une classe sont directement utilisables par les méthodes de cette classe.
- l'utilisation de this n'est pas une nécessité;
- le codage des constructeurs pose encore parfois problème: étudiez le corrigé
... et voici donc enfin un codage possible :
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
const int MAX_X(100);
const int MAX_Y(100);
const int MEETING_RADIUS(3);
/* Une classe pour représenter les animaux
*
*/
class Animal{
public:
Animal(int x, int y);
int get_x() const ;
int get_y() const;
void right(unsigned int);
void left(unsigned int);
void up(unsigned int);
void down(unsigned int);
// il est mieux de la definir en virtuelle pure
// car on ne sait pas a ce stade qui va etre un predateur
// ou une proie
virtual bool isPrey() const = 0;
virtual string getName() const {return "Animal";};
void setSick(bool sick_)
{
sick = sick_;
}
void die()
{
dead = true;
}
bool isSick() const
{
return sick;
}
bool isDead() const
{
return dead;
}
// methode virtuelle pure
// gerant les interactions entre animaux
virtual void meet(Animal*) = 0;
//teste si deux animaux peuvent interagir
bool canMeet(Animal*) const;
double distanceTo(const Animal&) const;
protected:
int x;
int y;
bool sick;
bool dead;
};
/* Une sous-classe pour les proies
*/
class Prey : public Animal {
public:
Prey(int x, int y);
bool isPrey() const {
return true;
}
string getName() const
{
return "Proie";
}
void meet(Animal*);
};
/* Une sous-classe pour les predateurs
*/
class Predator : public Animal{
public:
Predator(int x, int y);
bool isPrey() const {return false;
}
void meet(Animal*);
string getName() const
{
return "Predateur";
}
};
Animal::Animal(int x_, int y_) : x(x_), y(y_), sick(false), dead(false)
{
// Attention aux conditions limites
if(x > MAX_X) x = MAX_X;
if(x < 0) x = 0;
if(y > MAX_Y) y = MAX_Y;
if(y < 0) y = 0;
}
int Animal::get_x() const {
return x;
}
int Animal::get_y() const{
return y;
}
void Animal::right(unsigned int units){
x += units;
if(x > MAX_X) x = MAX_X;
}
void Animal::left(unsigned int units){
x -= units;
if(x < 0) x = 0;
}
void Animal::up(unsigned int units){
y += units;
if(y > MAX_Y) y = MAX_Y;
}
void Animal::down(unsigned int units){
y -= units;
if(y < 0) y = 0;
}
// calcule la distance d'un animal a un autre
double Animal::distanceTo(const Animal& otherAnimal) const {
return sqrt(pow((x-otherAnimal.get_x()),2) + pow((y-otherAnimal.get_y()),2));
}
// pour un affichage polymorphique : on utilise la virtualit'e des methodes
// appel'ees
ostream& operator<<(ostream& out, Animal& animal){
out << animal.getName() << " en ("<< animal.get_x() << ',' << animal.get_y() << ')';
if (animal.isDead())
out << ": animal mort";
else
if (animal.isSick())
out << ": animal malade";
else
out << ": animal sain";
return out;
}
Prey::Prey(int x, int y) : Animal(x,y){}
bool Animal::canMeet(Animal* otherAnimal) const
{
return (!isDead() && !(otherAnimal->isDead()) &&
distanceTo(*otherAnimal) <= MEETING_RADIUS);
}
void Prey::meet(Animal* otherAnimal){
if (canMeet(otherAnimal))
{
if (!otherAnimal->isPrey() && !isSick())
{
die();
}
}
}
Predator::Predator(int x, int y) : Animal(x,y) {}
void Predator::meet(Animal* otherAnimal){
if (canMeet(otherAnimal))
{
if (otherAnimal->isPrey() && !otherAnimal->isSick())
{
otherAnimal->die();
}
}
}
//PROGRAMME PRINCIPAL (fourni)
int main(){
/* TEST1
*/
cout << "Test de la partie 1 :" <<endl;
cout << "--------------------" << endl;
Animal* animal1(new Predator(0,0));
Animal* animal2(new Prey(25,0));
Animal* animal3(new Predator(10000,100000));
Animal* animal4(new Prey(-200,100000));
cout << *animal1 << endl;
cout << *animal2 << endl;
cout << "Distance : ";
cout << animal1->distanceTo(*animal2) << endl;
cout << *animal3 << endl;
cout << *animal4 << endl;
animal1->setSick(true);
cout << *animal1 << endl;
animal1->up(10000);
cout << *animal1 << endl;
animal1->left(200);
cout << *animal1 << endl;
animal1->die();
cout << *animal1 << endl;
delete animal1;
delete animal2;
delete animal3;
delete animal4;
/*FIN TEST 1*/
/* TEST2 */
cout << endl;
cout << "Test de la partie 2:" <<endl;
cout << "--------------------" << endl;
cout << "Proie saine, Predateur trop eloignes :" << endl;
animal1 = new Prey(0,0);
animal2 = new Predator(5,5);
cout << *animal1 << endl;
cout << *animal2 << endl;
cout << "apres tentative de rencontre : " << endl;
animal1->meet(animal2);
cout << *animal1 << endl;
cout << *animal2 << endl;
cout << endl;
cout << "Proie malade, Predateur se rencontrent :" << endl;
animal1->setSick(true);
animal2->left(4);
animal2->down(4);
cout << *animal1 << endl;
cout << *animal2 << endl;
cout << "apres rencontre (dans les deux sens): " << endl;
animal1->meet(animal2);
cout << *animal1 << endl;
cout << *animal2 << endl;
animal2->meet(animal1);
cout << *animal2 << endl;
cout << *animal1 << endl;
cout << endl;
cout << "Proie saine, Predateur se rencontrent :" << endl;
animal1->setSick(false);
animal2->setSick(false);
cout << *animal1 << endl;
cout << *animal2 << endl;
cout << "apres rencontre :" << endl;
animal1->meet(animal2);
cout << *animal1 << endl;
cout << *animal2 << endl;
cout << endl;
cout << "Predateur, Proie saine se rencontrent :" << endl;
animal3 = new Prey(2,2);
cout << *animal2 << endl;
cout << *animal3<< endl;
cout << "apres rencontre :" << endl;
animal2->meet(animal3);
cout << *animal2 << endl;
cout << *animal3 << endl;
cout << endl;
delete animal1;
animal1 = 0;
delete animal2;
animal2 = 0;
delete animal3;
animal3 = 0;
cout << "Deux proies saines de rencontrent:" << endl;
animal1 = new Prey(20,20);
animal2 = new Prey(10,10);
animal2->up(8);
animal2->right(8);
cout << *animal1 << endl;
cout << *animal2 << endl;
cout << "apres rencontre : " << endl;
animal1->meet(animal2);
cout << *animal1 << endl;
cout << *animal2 << endl;
cout << endl;
delete animal1;
animal1 = 0;
delete animal2;
animal2 = 0;
cout << "Deux predateurs se rencontrent:" << endl;
animal1 = new Predator(20,20);
animal2 = new Predator(10,10);
animal2->up(8);
animal2->right(8);
cout << *animal1 << endl;
cout << *animal2 << endl;
cout << "apres rencontre :" << endl;
animal1->meet(animal2);
cout << *animal1 << endl;
cout << *animal2 << endl;
delete animal1;
animal1 = 0;
delete animal2;
animal2 = 0;
/* FIN TEST2*/
return 0;
}
Exercice 2: durée de vie des variables
#include <iostream>
#include<vector>
#include<string>
using namespace std;
class Composant
{
public:
Composant(string nom, double quantite)
:nom_(nom), quantite_(quantite)
{}
void afficher(ostream& out) const
{
out << nom_ << " " << quantite_ << endl;
}
private:
string nom_;
double quantite_;
};
class Dosage : public vector<Composant*>
{
public:
/*
* le probleme est du au fait que cette methode ajoute au vecteur
* l'adresse d'une variable locale.
* Cette variable etant detruite a la fin de l'execution de la methode
* le pointeur stock'e dans la collection sera invalide
*/
void ajouter_composant(string nom, double quantite)
{
Composant c(nom, quantite);
push_back(&c);
/* Solution: allocation dynamique
push_back(new Composant(nom,quantite));
*/
}
void afficher(ostream& out) const
{
for (int i(0); i < size(); ++i)
(*this)[i]->afficher(out);
}
void vider()
{
for (int i(0); i < size(); ++i)
delete (*this)[i];
clear();
}
};
int main()
{
Dosage d;
d.ajouter_composant("alcool", 0.3);
d.ajouter_composant("formol", 0.4);
d.afficher(cout);
d.vider();
return 0;
}