C++ Mooc
C++ Mooc
C++ Mooc
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
; }
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]