Nous allons poursuivre avec l'exemple étudié au chapitre précédent, en remplaçant la fonction membre "initialise()" par un constructeur. On ajoutera également un destructeur. Pour simplifier nous avons également supprimé les fonctions afficher(). Voici la nouvelle déclaration :
class Navire
{
private:
string m_nom;
int m_x;
int m_y;
public:
Navire (string,
int,
int);
// Constructeur de la classe Navire
~Navire ();
// Destructeur
};
Nous effectuons la même transformation pour la classe SousMarin qui hérite de la classe Navire :
class SousMarin :
public Navire
{
private:
int
m_profondeur;
public:
SousMarin(string,
int,
int,
int);
// Constructeur de la classe SousMarin
~SousMarin ();
// Destructeur
};
Passons maintenant aux définitions. Celles de la classe mère ne posent aucun problème (Au besoin revoir le chapitre sur les constructeurs et destructeurs).
Navire::Navire(string nom,
int x,
int y)
{
cout
<<
"Construction d'un navire "
<< nom
<<
endl;
m_nom = nom;
m_x = x;
m_y = y;
}
Navire::~Navire()
{
cout
<<
"Destruction d'un navire "
<< m_nom
<<
endl;
}
Et maintenant les définitions de la classe fille. Vous attendiez le petit truc qu'il ne faut pas rater, nous y voici. Observez bien la première ligne de la définition de la classe SousMarin :
SousMarin::SousMarin(string
nom,
int x,
int y,
int profondeur)
:
Navire (nom,
x, y)
{
cout
<<
"Construction d'un sous marin "
<< nom
<<
endl;
m_profondeur = profondeur;
}
SousMarin::~SousMarin()
{
cout
<<
"Destruction d'un sous marin."
<<
endl;
}
Je suppose que vous avez trouvé, nous avons ajouté
:
Navire (nom,
x, y)
au bout de la première ligne.
Qu'est ce que celà va changer ?
Le constructeur SousMarin commence par transmettre le nom et la position (x, et y)
au constructeur Navire,
et c'est donc un navire (notre sous marin est un navire) qui est créé en premier.
Ensuite le constructeur SousMarin crée le sous marin en y ajoutant la profondeur.
Les destructeur font exactement et automatiquement l'inverse en détruisant le
sous marin, puis ensuite le navire que représentait ce sous marin.
Ecrivons la partie "main()" qui utilise ces deux classes :
int main()
{
Navire
nav("cargo",
5,
6);
SousMarin
sm("Uboat",
2,
2,
30);
return 0;
}
Une fois exécuté, le programme nous montre de façon évidente dans quel ordre se font les constructions, et destructions d'objets.
Construction d'un navire cargo
Construction d'un navire UBoat
Construction d'un sous marin UBoat
Destruction d'un sous marin.
Destruction d'un navire UBoat
Destruction d'un navire cargo
Si A est une classe, et B une classe qui hérite de A, alors la définition du constructeur de la classe B prendra la forme :
B::B(type1
arg1,
type2 arg2, ...) :
A(argx,
argy, ...)
{
...
}
où argx, argy, ... désignent les arguments appartenant à la liste arg1, arg2, ...,
qui doivent être transmis à la classe A.
Le constructeur A est appelé en premier, puis c'est au tour du constructeur de B.
C'est le sens inverse pour les destructeurs.
Vous avez peut être remarqué que j'ai omis de mettre "m_nom" dans la définition du
destructeur ~SousMarin. L'ajouter conduirait à une erreur de compilation
car cette variable membre est privée, et appartient uniquement à la classe Navire.
Heureusement il existe un moyen de maintenir l'encapsulation des variables membres
tout en autorisant l'accès de ces variables aux classes héritées.
Dans la déclaration, nous modifions simplement le statut privé (private) en statut
protégé (protected).
Voilà ce que donne cette transformation :
class Navire
{
protected:
// Variables membres protégées
string m_nom;
int m_x;
int m_y;
public:
Navire (string,
int,
int);
// Constructeur de la classe Navire
~Navire ();
// Destructeur
};
Maintenant nous pouvons réécrire notre définition du destructeur ~SousMarin :
SousMarin::~SousMarin()
{
cout
<<
"Destruction d'un sous marin "
<< m_nom
<<
endl;
}