Comme conséquence de cette notion d'héritage, on pourra toujours considérer un objet d'une classe dérivée comme un objet d'une classe de base. C'est vrai en particulier pour les pointeurs et les références.
Mais attention, si la conversion de classe dérivée vers classe de base ne pose aucun problème (car un objet de la classe dérivée c'est un objet de la classe de base plus quelque chose), de la classe de base vers la classe dérivée, la conversion ne peut pas être automatique, car en général, le ``quelque chose'' en plus de la classe dérivée risque de ne pas être alloué.
classe base{ int i; }; classe derivee{ int j; }; void essai(){ base b; derivee d; base *pb; derivee *pd; // a priori sizeof(b)==sizeof(int) // et sizeof(d)==2*sizeof(int) b=d; // ok d est un base d=b; // non pb=&d; // ok pd=&b; // non ou se trouve pd->j ?? };
Cependant, comme on le verra dans le paragraphe concernant la liaison
dynamique, l'affectation de pointeur ou de référence n'est pas identique
à l'affectation d'objets : pour l'affectation
b=d;
, seule la
partie base
(c'est-à-dire uniquement les données membres de la
partie base) sera copiée, alors que dans l'affectation de
pointeur
pb=&d;
pb sera initialisé par l'adresse de la partie
base
de d. En ce sens, pb bien qu'étant défini
comme un pointeur
sur base est en fait un pointeur sur derivee.
On peut définir des constructeurs permettant de convertir un objet d'une classe dérivée vers une classe de base ou d'une classe de base vers une classe dérivée :
class derive; class base{ protected: int i; public: //... base(const base&); // constructeur de copie base(); // constructeur par defaut base(const derive &); // conversion derive->base }; class derive: public base{ protected: int j; base::i; public: //... derive(const base &); // conversion base->derive }; base::base(const derive & d){ /*...*/}; //... base b1; derive d1=b1; base b2=d1;
derive d1=b1;
appellera derive(const base &)
, et
base b2=d1;
appellera base(const derive &)
. (Si ce
constructeur n'avait pas été défini, base b2=d1;
aurait appelé le
constructeur de copie base(const base&)
.
Notons enfin, qu'un cast explicite peut convertir une adresse d'objet d'une classe de base en une adresse d'objet d'une classe dérivée (avec les risques éventuels que cela implique.