C++ Mooc

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 10

MOOC Intro POO C++

Tutoriels semaine 2 : constructeurs/destructeurs


Les tutoriels sont des exercices qui reprennent des exemples similaires ceux du cours et dont le corrig est donn progressivement au fur et
mesure de la donne de l'exercice lui-mme.
Ils sont conseills comme un premier exercice sur un sujet que l'tudiant ne pense pas encore assez matriser pour aborder par lui-mme un
exercice classique.
Les solutions sont fournies au fur et mesure sur les pages paires.
Cet exercice correspond l'exercice pas pas page 113 de l'ouvrage C++ par la
pratique (3e dition, PPUR).
Le but de cet exercice est d'illustrer par un exemple dtaill, d'une part la manire d'crire les constructeurs et destructeurs, et d'autre part de
mettre en vidence leur fonctionnement.
On propose pour cela de jouer avec des animaux en peluche. Ces peluches seront caractrises par l'espce de l'animal reprsent, le nom
donn la peluche ainsi que son prix de vente.
Avec vos connaissances de la semaine passe, commencez crire une premire base pour modeliser les animaux en peluche (attributs,
accesseurs, modificateur). On considrera que les attributs espece et nom ne changent plus une fois qu'une peluche d'une espce donne
est fabrique (on ne la transforme pas en une autre), ce qui n'est pas le cas du prix ; on fournira donc pour ce seul attribut une mthode
permettant d'en changer la valeur.
Essayez de le faire par vous mme sans regarder la solution. (solution page suivante)

Solution :
class Peluche {
private:
string espece;
string nom;
double prix;
public:
string getEspece() const
string getNom()
const
double getPrix()
const

{ return espece ; }
{ return nom
; }
{ return prix
; }

void setPrix(double valeur) { prix = valeur; }


};

Dotons maintenant le programme d'une fonction etiquette, prenant une Peluche en argument et ralisant l'affichage (sur le terminal)
de ce que pourrait tre l'tiquette de cette peluche. Ceux qui objecteraient que l'affichage de l'tiquette devrait plutt tre une mthode de la
classe Peluche ont tout fait raison ! Mais pour des raisons pdagogiques qui seront plus claires par la suite, nous avons besoin d'une
fonction externe .
Ajoutons galement un main() minimaliste, qui instancie une peluche et demande l'affichage de son tiquette.
(solution page suivante)

Solution :
void etiquette(Peluche p) {
cout << "Hello, mon nom est " << p.getNom() << endl
<< "Je suis un " << p.getEspece() << " et je coute "
<< p.getPrix() << " francs." << endl;
}
int main() {
Peluche bobo;
// On utilise le constructeur par dfaut
cout << "Etiquette :" << endl;
etiquette(bobo);
return 0;
}

Le programme compile sans problme, mais donne un rsultat trange lors de l'excution, par exemple :
Etiquette :
Hello, mon nom est
Je suis un et je coute 10.3413 francs.
Le constructeur par dfaut fourni par le compilateur s'excute bien en tout dbut de programme, mais on se rend compte qu'aucun nom ni
espce n'est affich, et surtout que le prix est fantaisiste. Cela se produit parce qu'une erreur flagrante a t commise lors de l'criture de ce
programme : le contenu de certaines variables a t utilis sans qu'elles aient t pralablement initialises. Le constructeur par dfaut fourni
par le compilateur n'initialise en effet pas les grandeurs de type de base (int, double, ...).
L'intrt des constructeurs est justement d'offrir un moyen lgant pour viter ce genre d'oublis. On peut justement remarquer que les
attributs disposant d'un constructeur par dfaut (dans le cas prsent, les deux string) ont t initialiss (ici par la chane vide) malgr cet
oubli. Ces constructeurs ont effectivement t invoqus, de la mme manire que le constructeur par dfaut de Peluche est invoqu
lorsque l'on crit :
Peluche bobo;
Donner, dans le constructeur par dfaut, une valeur spcifique aux attributs (en particulier ceux qui n'admettent pas eux-mmes de
constructeurs par dfaut) serait une possibilit, mais peu satisfaisante dans le cas prsent : comme l'utilisation de constantes a t choisie, il
est impratif de les initialiser avec une valeur pertinente.
La solution est d'utiliser pour cela un constructeur explicite, et non pas le constructeur par dfaut (qui n'a gure sa place dans un tel
exemple). Les arguments de ce constructeur sont ncessairement le nom donner la peluche, son espce ainsi qu'une valeur de dpart pour
le prix (qui est le seul lment pouvoir tre modifi ultrieurement).
l'excution, le programme devrait afficher :
[Une peluche est fabrique]
Etiquette :
Hello, mon nom est Bobo
Je suis un ours et je coute 14.95 francs.
Essayez de le faire par vous mme sans regarder la solution. (solution page suivante)

Solution :
class Peluche {
// ...
Peluche(string espece, string nom, double prixAchat)
: espece(espece), nom(nom), prix(prixAchat)
{
cout << "[Une peluche est fabrique]" << endl;
}
// ...
};
//...
int main() {
Peluche bobo("ours", "Bobo", 14.95);
cout << "Etiquette :" << endl;
etiquette(bobo);
return 0;
}

Ajoutons maintenant un constructeur de copie explicite (donc en remplacement de celui gnr automatiquement par le compilateur -- avec
ou sans attributs constants cette fois), en apportant une subtilit : au lieu de raliser une copie parfaite, ce constructeur altrera lgrement le
nom de la peluche qu'il doit copier, ce qui permettra de distinguer, lors de l'affichage de l'tiquette, les copies des originaux, par exemple :
[Une peluche est fabrique]
Etiquette :
[Une peluche a t copie]
Hello, mon nom est Bobo-copie
Je suis un ours et je coute 14.95 francs.
(solution page suivante)

Solution :
class Peluche {
// ...
Peluche(Peluche const& p)
: espece(p.espece), nom(p.nom + "-copie"), prix(p.prix)
{
cout << "[Une peluche a t copie]" << endl;
}
// ...
};

A noter que nous n'avons pas eu besoin de changer le main() pour avoir de copie !
H oui ! C'est bien l'tiquette d'une copie de la peluche Bobo qui est affiche. La raison est simple : la fonction etiquette prend une
Peluche en paramtre, au travers d'un passage par valeur ; cette fonction travaille donc sur une copie (locale) de la peluche utilise en
argument de l'appel. C'est justement pour illustrer ce point que nous voulions une fonction externe.
Pour viter cela, il faut bien entendu utiliser un passage par rfrence, et en l'occurrence, par une rfrence constante puisque etiquette
n'a pas modifier la peluche reue en argument :
void etiquette(const Peluche& p) { ... }
l'excution du programme, on constate qu'il n'y a plus d'appel au constructeur de copie.
Ajoutons maintenant un destructeur explicite (l aussi, en remplacement de celui gnr automatiquement), et modifions quelque peu les
messages des constructeurs prcdents de sorte qu'ils affichent le nom de la peluche concerne. Ajoutons galement quelques peluches de
plus dans le main Le programme complet est alors :
(solution page suivante)

Solution :
#include <string>
#include <iostream>
using namespace std;
class Peluche
{
public:
Peluche(string espece, string nom, double prixAchat)
: espece(espece), nom(nom), prix(prixAchat)
{ cout << "[La peluche " << nom << " est fabrique]" << endl; }
Peluche(Peluche const& p)
: espece(p.espece), nom(p.nom+"-copie"), prix(p.prix)
{ cout << "[La peluche " << p.nom << " a t copie en " << nom << "]" << endl; }
~Peluche()
{ cout << "[La peluche " << nom << " est casse]" << endl; }
string getEspece() const { return espece; }
string getNom()
const { return nom
; }
double getPrix()
const { return prix ; }
void setPrix(double valeur) { prix = valeur; }
private:
const string espece;
const string nom;
double prix;
};
void etiquette(Peluche const& p)
{
cout << "Hello, mon nom est " << p.getNom() << endl
<< "Je suis un " << p.getEspece() << " et je coute "
<< p.getPrix() << " francs." << endl;
}
int main()
{
Peluche bobo("ours", "Bobo", 14.95);
cout << "Etiquette :" << endl;
etiquette(bobo);
Peluche* bello; // pas encore d'objet, juste un pointeur
{
Peluche ssss("cobra", "Ssss", 10.00);
bello = new Peluche("toucan", "Bello", 20.00);
}
Peluche bello_clone(*bello);
etiquette(bello_clone);
delete bello;
return 0;
}
Son excution donne :
[La peluche Bobo est fabrique]
Etiquette :
Hello, mon nom est Bobo
Je suis un ours et je coute 14.95 francs.
[La peluche Ssss est fabrique]
[La peluche Bello est fabrique]
[La peluche Ssss est casse]
[La peluche Bello a t copie en Bello-copie]
Hello, mon nom est Bello-copie
Je suis un toucan et je coute 20 francs.
[La peluche Bello est casse]
[La peluche Bello-copie est casse]
[La peluche Bobo est casse]

Vous aimerez peut-être aussi