Avez-vous essayé de programmer la méthode
nbrRoues() du mini-exercice ? Non ! Il est encore temps de le faire. Elle va beaucoup nous intéresser dans la suite.
Le problème des roues
Comme c'est un peu répétitif, je vous donne ma version de la fonction pour les classes véhicules et voiture uniquement.
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | class Vehicule
{
public:
Vehicule(int prix);
virtual void affiche() const;
virtual int nbrRoues() const; //Affiche le nombre de roues du véhicule
virtual ~Vehicule();
protected:
int m_prix;
};
class Voiture : public Vehicule
{
public:
Voiture(int prix, int portes);
virtual void affiche() const;
virtual int nbrRoues() const; //Affiche le nombre de roues de la voiture
virtual ~Voiture();
private:
int m_portes;
};
|
Du côté du .h, pas de soucis. C'est le corps des fonctions qui risque de poser problème.
Code : C++ | int Vehicule::nbrRoues() const
{
//Que mettre ici ????
}
int Voiture::nbrRoues() const
{
return 4;
}
|
Vous l'aurez compris, on ne sait pas vraiment quoi mettre dans la "version
Vehicule" de la méthode. Les voitures ont 4 roues et les motos 2, mais pour un véhicule en général, on ne peut rien dire ! On aimerait bien ne rien mettre ici ou carrément supprimer la fonction puisqu'elle n'a pas de sens.
Mais si on ne déclare pas la fonction dans la classe mère, alors on ne pourra pas l'utiliser depuis notre collection hétérogène. Il nous faut donc la garder ou au minimum dire qu'elle existe mais qu'on n'a pas le droit de l'utiliser. On souhaiterait ainsi dire au compilateur :
« Dans toutes les classes filles de Vehicule, il y aura une fonction nommée nbrRoues() qui renvoie un int et qui ne prend aucun argument, mais dans la classe Vehicule, cette fonction n'existe pas. »
C'est ce qu'on appelle une
méthode virtuelle pure.
Pour déclarer une telle méthode, rien de plus simple. Il suffit d'ajouter
= 0 à la fin du prototype.
Code : C++ - Une fonction virtuelle pure | class Vehicule
{
public:
Vehicule(int prix);
virtual void affiche() const;
virtual int nbrRoues() const = 0; //Affiche le nombre de roues du véhicule
virtual ~Vehicule();
protected:
int m_prix;
};
|
Et évidemment, on n'a rien à écrire dans le .cpp puisque justement on ne sait pas quoi y mettre. On peut carrément supprimer complètement la méthode. L'important étant que son prototype soit présent dans le .h.
Les classes abstraites
Une classe qui possède au moins une méthode virtuelle pure est une
classe abstraite. Notre classe
Vehicule est donc une classe abstraite.
Pourquoi donner un nom spécial à ces classes ? Eh bien, parce qu'elles ont une règle bien particulière :
On ne peut pas créer d'objet à partir d'une classe abstraite.

Oui, oui, vous avez bien lu ! La ligne suivante ne compilera pas.
Code : C++ | Vehicule v(10000); //Création d'un véhicule valant 10000 euros.
|
Dans le jargon des programmeurs, on dit qu'on ne peut pas créer d'instance d'une classe abstraite.
La raison est simple. Si je peux créer un
Vehicule, alors je pourrais essayer d'appeler la fonction
nbrRoues() qui n'a pas de corps et ceci n'est pas possible.
Je peux par contre tout à fait écrire le code suivant :
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12 | int main()
{
Vehicule* ptr(0); // Un pointeur sur un véhicule
Voiture caisse(20000,5); // On crée une voiture, ceci est autorisé puisque toutes les fonctions ont un corps.
ptr = &caisse; // On fait pointer le pointeur sur la voiture.
cout << ptr->nbrRoues() << endl; // Dans la classe fille nbrRoues() existe donc ceci est autorisé.
return 0;
}
|
Ici, l'appel à la méthode
nbrRoues() est polymorphique, puisque nous avons un pointeur et que notre méthode est virtuelle. C'est donc la "version
Voiture" qui est appelée. Donc même si la "version
Vehicule" n'existe pas, il n'y a pas de problèmes.
Si l'on veut créer une nouvelle sorte de
Vehicule (
Camion par exemple), on sera obligé de redéfinir la fonction
nbrRoues(), sinon cette dernière sera virtuelle pure par héritage et par conséquent la classe abstraite aussi.
On peut résumer les fonctions virtuelles de la manière suivante :
- Une méthode virtuelle peut être redéfinie dans une classe fille.
- Une méthode virtuelle pure doit être redéfinie dans une classe fille.
Dans la bibliothèque Qt, que nous allons très bientôt aborder, il y a beaucoup de classes abstraites. Il existe par exemple une classe par sorte de bouton, c'est-à-dire une classe pour les boutons normaux, une pour les cases à cocher, etc. Toutes ces classes héritent d'une classe nommée
QAbstractButton, qui regroupe des propriétés communes à tous les boutons (taille, texte, ...). Mais comme on ne veut pas autoriser les utilisateurs à mettre des
QAbstractButton sur leurs fenêtres, les créateurs de la bibliothèque ont rendu cette classe abstraite.
