Comme les interfaces sont si importantes, elles doivent être protégées d'éventuelles dégradations par l'inclusion de structures de données ou autres artifices d'implémentation. Vous devez donc séparer l'interface de l'implémentation.
[ Haut | Bas | Rechercher ]
[ Haut | Bas | Rechercher ]
Au niveau conceptuel, une classe de base abstraite (ABC) correspond à un concept abstrait. Si vous demandez à un mécanicien si il répare des véhicules, il vous demandera probablement à quelle sorte de(kind-of) véhicule vous faites allusion. Il y a de fortes chances qu'il ne répare pas de navettes spatiales, de transocéaniques, de vélos ou de sous-marin nucléaires. Le problème est que le terme "véhicule" est un concept abstrait (e.g., on ne peut construire un "véhicule" à moins de savoir précisément le type de véhicule à construire. En C++, la classe Vehicle devrait donc être une ABC, avec Bicycle, SpaceShuttle, etc, étant des classes dérivées (un OceanLiner est une sorte de Vehicle. Dans le monde réel de l'OO, les ABCs sont présentes en grandes quantités.
Au niveau langage de programmation, une ABC est une classe qui a une ou plusieurs fonctions virtuelles pures. On ne peut pas créer un objet (instance) correspondant à une ABC.
[ Haut | Bas | Rechercher ]
Des fonctions membres existent d'un point de vue conceptuel mais n'ont pas de définition concrète. Par exemple, supposons que l'on vous demande de dessiner une Shape (forme géométrique) au point (x,y) qui a une taille de 7. Vous allez demander "quelle forme géométrique dois-je dessiner?" (cercle, carré, hexagones, etc..sont dessinés de façons différentes). En C++, on doit indiquer l'existence de la fonction membre draw() (de cette manière l'utilisateur peut l'appeler lorsqu'ils ont un Shape* ou un Shape&), mais on ne peut l'implémenter (logiquement) que dans les classes dérivées.
class Shape { public: virtual void draw() const = 0; // = 0 signifie "virtuelle pure" // ... };
Cette fonction virtuelle pure fait de Shape une ABC. Si vous le souhaitez, vous pouvez imaginer la syntaxe "= 0;" comme si le code était pointé par NULL. Donc Shape promet un service à ses utilisateurs, cependant Shape est incapable de fournir le code pouvant répondre à cette promesse. Cela force n'importe quel objet créé à partir d'une classe [concrète] dérivée de Shape à avoir la fonction membre indiquée, même si la classe de base ne dispose pas de suffisamment d'informations pour la définir.
Notez bien que l'on peut fournir une définition pour une fonction virtuelle pure, mais cela embrouille généralement les débutants et il est préférable de l'éviter pour l'instant.
[ Haut | Bas | Rechercher ]
Si la classe possède l'objet pointé par le biais d'un pointeur de la classe de base (abstraite), alors on peut utiliser l'idiome du constructeur virtuel (Virtual Constructor Idiom) dans la classe de base (abstraite). Comme à l'habitude avec cet idiome, on déclare une method clone() virtuelle pure dans la classe de base:
class Shape {
public:
// ...
virtual Shape* clone()
const = 0; // Le constructeur de copie virtuel
// ...
};
On implémente la méthode clone() dans chaque classe dérivée:
class Circle : public Shape {
public:
// ...
virtual
Shape* clone() const { return new Circle(*this); }
// ...
};
class Square
: public Shape {
public:
// ...
virtual Shape* clone()
const { return new Square(*this); }
// ...
};
Maintenant supposons que chaque objet Fred possède un objet Shape(relation has-a). Naturellement , l'objet Fred ne sait pas si la forme (Shape) est un cercle (Circle ) ou un carré (Square) ou...etc..etc.. Le constructeur de copié et l'opérateur d'affectation de Fred va alors appeler la méthode clone() de Shape afin de copier l'objet.
class Fred {
public:
Fred(Shape* p) : p_(p)
{ assert(p != NULL); } // p ne doit pas être
NULL
~Fred()
{ delete p_; }
Fred(const Fred& f) : p_(f.p_->clone()) { }
Fred& operator= (const Fred&
f)
{
if (this != &f) {
// vérifie l'auto affectation
Shape* p2 = f.p_->clone(); // D'ABORD on crée
le nouveau...
delete p_;
// ...Ensuite on efface l'ancien
p_ = p2;
}
return *this;
}
// ...
private:
Shape* p_;
};
[ Haut | Bas | Rechercher ]
Ecrire à l'auteur,
au traducteur,
ou en savoir plus sur la traduction.
C++ FAQ Lite fr |
Table des matières |
Index |
A propos de l'auteur |
© |
Téléchargez votre propre copie ]
Dernière révision Sun Apr 13 23:53:57 PDT 2003