| Exercice 1 | Exercice 2 |
Définissez une classe Forme en la dotant d'une méthode
qui affiche [...]
#include <iostream>
using namespace std;
class Forme {
public:
void description() const {
cout << "Ceci est une forme." << endl;
}
};
Ajoutez au programme une classe Cercle héritant
de la classe Forme, et possédant une méthode
void description()
qui affiche [...]
class Cercle : public Forme {
public:
void description() const {
cout << "Ceci est un cercle." << endl;
}
};
[...] Testez ensuite à nouveau votre programme.
Voyez-vous vu la nuance ?
Pourquoi a-t-on ce
fonctionnement ?
La différence vient de ce que c.description();
appelle la méthode description() de la classe
Cercle (c'est-à-dire Cercle::description()), alors que f2.description(); appelle celle de la classe Forme (c'est-à-dire Forme::description()), bien que elle ait été
construite par une copie d'un cercle.
Le polymorphisme n'opère pas ici car aucune des deux conditions nécessaires n'est remplie : la méthode n'est pas virtuelle et on ne passe par pas par des références ni pointeurs.
[...] Ajoutez encore au programme une fonction
void affichageDesc(Forme& f) [...]
Le résultat vous semble-t-il
satisfaisant ?
Avec cette fonction, nous apportons une solution au second aspect puisqu'en effet nous passons l'argument par référence.
Le résultat n'est cependant toujours pas satisfaisant (c'est
toujours la méthode Forme::description() qui est appelée) car le
premier problème subsiste : la méthode n'est pas virtuelle.
Modifiez le programme (ajoutez 1 seul mot) pour que le résultat soit plus conforme à ce que l'on pourrait attendre.
Il suffit donc d'ajouter virtual devant le
prototype de la méthode description de la classe
Forme.
Voici le programme complet :
#include <iostream>
using namespace std;
class Forme {
public:
virtual void description() const {
cout << "Ceci est une forme." << endl;
}
};
class Cercle : public Forme {
public:
void description() const {
cout << "Ceci est un cercle." << endl;
}
};
void affichageDesc(const Forme& f) { f.description(); }
int main()
{
Cercle c;
affichageDesc(c);
return 0;
}
Modifiez la classe Forme de manière à en faire
une classe abstraite [...]
class Forme {
public:
virtual void description() const {
cout << "Ceci est une forme !" << endl;
}
virtual double aire() const = 0;
};
Ce qui en fait une méthode virtuelle pure c'est le =0
derrière qui indique que pour cette classe cette méthode ne sera pas
implémentée (i.e. pas de définition, c.-à-d. pas de corps).
Écrivez une classe Triangle et
modifiez la classe Cercle existante héritant toutes
deux de la classe Forme, et implémentant les méthodes
aire() et description(). [...]
class Cercle : public Forme {
public:
Cercle(double r = 0.0) : rayon(r) {}
void description() const {
cout << "Ceci est un cercle !" << endl;
}
double aire() const { return M_PI * rayon * rayon; }
private:
double rayon;
};
class Triangle : public Forme {
public:
Triangle(double h = 0.0, double b = 0.0) : base(b), hauteur(h) {}
void description() const {
cout << "Ceci est un triangle !" << endl;
}
double aire() const { return 0.5 * base * hauteur; }
private:
double base; double hauteur;
};
Modifiez la fonction affichageDesc pour qu'elle
affiche, en
plus, l'aire [...]
void affichageDesc(Forme& f) {
f.description();
cout << " son aire est " << f.aire() << endl;
}
et le programme complet :
#include <iostream>
#include <cmath> // pour M_PI
using namespace std;
class Forme {
public:
virtual void description() const {
cout << "Ceci est une forme !" << endl;
}
virtual double aire() const = 0;
};
class Cercle : public Forme {
public:
Cercle(double r = 0.0) : rayon(r) {}
void description() const {
cout << "Ceci est un cercle !" << endl;
}
double aire() const { return M_PI * rayon * rayon; }
private:
double rayon;
};
class Triangle : public Forme {
public:
Triangle(double h = 0.0, double b = 0.0) : base(b), hauteur(h) {}
void description() const {
cout << "Ceci est un triangle !" << endl;
}
double aire() const { return 0.5 * base * hauteur; }
private:
double base; double hauteur;
};
void affichageDesc(Forme& f) {
f.description();
cout << " son aire est " << f.aire() << endl;
}
int main()
{
Cercle c(5);
Triangle t(10, 2);
affichageDesc(t);
affichageDesc(c);
return 0;
}
qui donne comme résultat :
Ceci est un triangle ! son aire est 10 Ceci est un cercle ! son aire est 78.5398
#include <iostream>
#include <array>
#include <vector>
#include <string>
using namespace std;
// ====================================================================
enum Couleur { vide = 0, rouge, jaune };
// ====================================================================
class Jeu {
public:
Jeu(size_t taille = 8);
bool jouer(size_t, Couleur);
Couleur gagnant() const;
bool fini(Couleur&) const;
size_t get_taille() const { return grille.size(); }
ostream& affiche(ostream& out) const;
protected:
vector< vector< Couleur > > grille;
private:
unsigned int compte(Couleur, size_t, size_t,
int, int) const;
};
// ------------------------------------------------------------
Jeu::Jeu(size_t taille)
: grille(taille, vector<Couleur>(taille, vide))
{}
// ------------------------------------------------------------
bool Jeu::jouer(size_t i, Couleur c) {
if (c == vide) return false;
if (i >= get_taille()) return false;
size_t j(0);
while ((j < get_taille()) and (grille[i][j] != vide)) ++j;
if (j >= get_taille()) return false;
grille[i][j] = c;
return true;
}
// ------------------------------------------------------------
Couleur Jeu::gagnant() const {
Couleur vainqueur(vide);
for (size_t i(0); i < get_taille(); ++i) {
for (size_t j(0); j < get_taille(); ++j) {
if (grille[i][j] != vide) {
vainqueur = grille[i][j];
// teste dans les 5 directions possibles (+ (0,0) qui ne fait
// rien)
for (int di(0); di <= 1; ++di)
for (int dj(-1); dj <= 1; ++dj)
if (compte(vainqueur, i, j, di, dj) >= 4) return vainqueur;
}
}
}
return vide;
}
// ------------------------------------------------------------
unsigned int Jeu::compte(Couleur couleur,
size_t i, size_t j,
int di, int dj) const
{
unsigned int n(1);
if ((di != 0) or (dj != 0)) {
for (i += di, j += dj;
(i < get_taille()) and (j < get_taille()) and (grille[i][j] == couleur);
i += di, j += dj)
++n;
}
return n;
}
// ------------------------------------------------------------
bool Jeu::fini(Couleur& resultat) const {
resultat = gagnant();
if (resultat == vide) {
// est-ce plein ?
for (auto ligne : grille) {
if (kase == vide)
return false;
}
}
}
return true;
}
// ------------------------------------------------------------
ostream& operator<<(ostream& out, const Jeu& jeu) {
return jeu.affiche(out);
}
ostream& Jeu::affiche(ostream& out) const {
for (auto ligne : grille) {
for (auto kase : ligne) {
switch (kase) {
case vide : out << ' '; break;
case rouge : out << '#'; break;
case jaune : out << 'O'; break;
}
}
out << endl;
}
for (size_t i(0); i < get_taille(); ++i) out << '-';
out << endl;
for (size_t i(1); i <= get_taille(); ++i) out << i;
out << endl;
return out;
}
// ====================================================================
class Joueur {
public:
Joueur(string nom, Couleur couleur = rouge)
: nom(nom), couleur(couleur) {}
virtual ~Joueur() {}
virtual void jouer(Jeu&) const = 0;
string get_nom() const { return nom; }
Couleur get_couleur() const { return couleur; }
protected:
string nom;
Couleur couleur;
};
// ====================================================================
class Partie {
public:
Partie(Joueur const*, Joueur const*);
void lancer();
void vider();
protected:
array<Joueur const*, 2> joueurs;
Jeu jeu;
};
// ------------------------------------------------------------
Partie::Partie(Joueur const* j1, Joueur const* j2) {
joueurs[0] = j1;
joueurs[1] = j2;
}
// ------------------------------------------------------------
void Partie::lancer() {
unsigned int tour(0);
Couleur vainqueur;
do {
joueurs[tour]->jouer(jeu);
tour = 1 - tour; // joueur suivant : 0 -> 1 1 -> 0
} while (not jeu.fini(vainqueur));
cout << "La partie est finie." << endl;
cout << jeu << endl;
if (vainqueur == joueurs[0]->get_couleur()) {
cout << "Le vainqueur est " << joueurs[0]->get_nom() << endl;
} else if (vainqueur == joueurs[1]->get_couleur()) {
cout << "Le vainqueur est " << joueurs[1]->get_nom() << endl;
} else {
cout << "Match nul." << endl;
}
}
// ------------------------------------------------------------
void Partie::vider() {
for (auto joueur : joueurs) delete joueur;
}
// ====================================================================
class Humain : public Joueur {
public:
Humain(Couleur couleur = rouge) : Joueur("quidam", couleur) {
cout << "Entrez votre nom : " << flush;
cin >> nom;
}
void jouer(Jeu&) const;
};
// ------------------------------------------------------------
void Humain::jouer(Jeu& jeu) const {
cout << jeu << endl;
size_t lu;
bool valide;
do {
<< " (entre 1 et " << jeu.get_taille() << ") : ";
cin >> lu; // on pourrait faire ici la validation de la lecture
valide = jeu.jouer(lu, couleur);
if (not valide) cout << "-> Coup NON valide." << endl;
} while (not valide);
}
// ====================================================================
class Ordi : public Joueur {
public:
Ordi(Couleur couleur = jaune) : Joueur("Le programme", couleur) {}
void jouer(Jeu&) const;
};
// ------------------------------------------------------------
void Ordi::jouer(Jeu& jeu) const {
for (size_t i(0); i < jeu.get_taille(); ++i) {
if (jeu.jouer(i, couleur)) {
return;
}
}
}
// ====================================================================
int main()
{
Partie p(new Ordi(rouge), new Humain(jaune));
p.lancer();
p.vider();
return 0;
}