1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| struct Mere
{
// destructeur virtuel
virtual ~Mere() {}
// accesseur au seul attribut
std::string const& nom() const { return nom_; }
// La seule façon d'obtenir une copie polymorphique
virtual Mere * clone() const = 0;
protected:
// Aucun intérêt à être public, la classe n'est pas instanciable
// Mais c'est requis par les descendants => protégé
Mere(std::string const& un_nom) : nom_(un_nom) {}
// Constructeur de recopie. Etre public n'a aucun sens dans
// une hiérarchie car le polymorphisme se perdrait.
// De plus, c'est requis par les constructeurs de copie de descendants,
// => protégé
Mere(Mere const& rhs) : nom_(rhs.nom()) {}
private:
// Constructeur par défaut interdit jusqu'à preuve de la
// nécessité contraire
Mere();
// Avoir un opérateur d'affection n'a aucun sens dans une
// hiérarchie polymorphique!!!
// => déclaré privé, non défini (<=> interdit)
Mere& operator=(Mere const&)
// implémentation de la propriété nom de la classe. C'est un
// détail d'implémentation, on encapsule donc => privé
std::string nom_;
};
// héritage public (<=> polymorphisme d'héritage/inclusion/substitution,
// les objets Fille sont sustituables là où l'on attend des objets Mere;
// google => LSP)
struct Fille : Mere
{
virtual ~Fille() {}
Attrb attrb() const { return attrb_; }
// On implémente le clonage là où cela a du sens
// Le type de retour change ; google => retour covariant
virtual Fille * clone() const {return Fille(*this); }
// Constructeur initialisant. Il est public pour pouvoir générer
// de tels objets depuis n'importe où
// Il profite du constructeur initialisant de la classe mère, qui est
// la seule à savoir comment est implémentée la propriété nom
Fille(std::string const& un_nom, Attrb a)
: Mere(un_nom)
, attrb_(a)
{}
protected:
// Constructeur de recopie utilisé par la fonction clone
// l'utiliser depuis ailleurs n'a aucun sens => protégé, au cas où la
// classe devrait encore être dérivée, privé suffirait sinon
// Il profite du constructeur de recopie (protégé!) de la classe mère,
// toujours la seule classe à savoir pour la propriété nom
Fille(Fille const& rhs)
: Mere(rhs)
, attrb_(rhs.attrb())
{}
private:
Fille(); // interdit jusqu'à preuve du besoin contraire
Fille& operator=(Fille const&); // interdit à tout jamais
Attrb attrb_; // implémentation d'un nouvel attribut
}; |
Partager