User Tools

Site Tools


in204:cpp:syntax:class:deriving

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
in204:cpp:syntax:class:deriving [2019/09/23 20:24]
bmonsuez [Déclare une classe dérivée]
in204:cpp:syntax:class:deriving [2022/11/18 10:51] (current)
Line 1: Line 1:
-====== ​La classe ​dérivée ======+====== ​Classe ​dérivée ​& héritage ​======
  
-La classe dérivée est une **extension** ​d'une classe ​de base. C'est une classe à laquelle on a ajouté des __champs__ et des __fonctions membres__ supplémentaires.+===== Pourquoi hériter ​d'une classe ​====
  
-La classe dérivée ''​hérite''​ de l'​ensemble des __fonctions membres__ et des __champs__ définis par la ou les classes de bases. C'est pour cela que l'on parle d'​héritage quand on parle de classes dérivées d'une autre classe.+Supposons ​que nous avons réaliser un objet qui effectuer une certaine tâche ​de base
  
-===== Déclare ​une classe dérivée ​====+<code cpp> 
 +class enumerate_characters 
 +
 +private: 
 +  int mPosition;​ 
 +  int mNumberOfCharacters;​ 
 +  const char* mString; 
 +public: 
 +  enumerate_characters(const char* aString, int theNumberOfCharacters):​ 
 +      mString(aString),​ mNumberOfCharacters(theNumberOfCharacters) {} 
 +   
 +  int next() 
 +  { 
 +      return mPosition < mNumberOfCharacters ?  
 +        (int)mString[mPosition++] : -1; 
 +  } 
 +  void reset() 
 +  { 
 +      mPosition ​0; 
 +  } 
 +
 +</​code>​ 
 + 
 +Cette classe énumère les caractère de la chaîne de caractère passée en paramètre en commençant par le premier caractère et en terminant par le dernier caractère. 
 + 
 +Supposant que je ne souhaite plus énumérer les caractères en commençant par le premier caractère et en terminant par le dernier caractère mais à l'​inverse en commençant par le dernier caractère et en terminant par le premier. Je devrais ajouter à cette classe la fonction ''​previous()''​ par exemple. Je peux soit ajouter cette méthode dans la classe ou au contraire ajouter cette méthode à une extension de la classe, ce que l'on appelle ​une classe dérivée ​ou une classe fille qui hérite de son parent. L'​intérêt est dans ce cas que je vais pouvoir modifier le comportement de la classe.
  
-La syntax pour déclarée une classe comme héritant d'une classe de base est la suivante : 
 <code cpp> <code cpp>
 +class enumerate_characters
 +{
 +private:
 +  int mPosition;
 +protected:
 +  int mNumberOfCharacters;​
 +  const char* mString;
 +public:
 +  enumerate_characters(const char* aString, int theNumberOfCharacters):​
 +      mString(aString),​ mNumberOfCharacters(theNumberOfCharacters) {}
 +  ​
 +  int next()
 +  {
 +      return mPosition < mNumberOfCharacters ? 
 +        (int)mString[mPosition++] : -1;
 +  }
 +  void reset()
 +  {
 +      mPosition = 0;
 +  }
 +}
  
-class DerivingClasspublic BaseClass+class bidi_enumerate_charactersenumerate_characters
 { {
-};+private: 
 +  int mReversePosition;​ 
 +public: 
 +  bidi_enumerate_characters(const char* aString, int theNumberOfCharacters):​ 
 +      enumerate_characters(aString,​ theNumberOfCharacters),​ mReversePosition(theNumberOfCharacters) {} 
 +   
 +  int previous() 
 +  { 
 +      return mReversePosition >= 0 ?  
 +        (int)mString[mPosition++] : -1; 
 +  } 
 +  void reset() 
 +  { 
 +      mReversePosition= mNumberOfCharacters;​ 
 +      enumerate_characters()::​reset();​ 
 +  } 
 +
 +</​code>​
  
 +La classe ''​bidi_enumerate_characters''​ est une extension de la classe ''​enumerate_characters''​ :
 +
 +<code cpp>
 +class bidi_enumerate_characters:​ enumerate_characters
 +{
 </​code>​ </​code>​
  
-Cette définition indique que la classe ''​DerivingClass''​ hérite de la classe ''​BaseClass''​ et donc que l'​ensemble ​des méthodes et des champs ​définis par la classe ''​BaseClass''​ sont présents dans la classe ''​DerivingClass''​. ​Cependantil faut faire attention, présent ​ne veut pas dire qu'​ils ​sont accessibles ​dans la classe de baseAinsi, nous avons les règles d'accessibilité suivantes pour les méthodes ​et les champs définis ​dans la classe de base.+ce qui veut que l'​ensemble des champs ​et méthodes présents dans la classe ''​enumerate_characters''​ sont présents dans la classe ''​bidi_enumerate_characters''​. ​Attentionles champs ou méthodes privées sont présentes mais ne sont pas accessibles. ​Ici, nous avons besoin des champs ''​mNumberOfCharacters'​' et ''​mString'' ​dans la classe dérivée, c'est pour cela que nous avons modifié ​la classe de base ''​enumerate_characters''​ pour les rendre toujours inaccessibles en dehors de la classe mais accessible dans les classes derivées en les déclarant comme ''​proctected''​ :
  
-^ Déclaration dans la classe de base ^ Accesibilité dans la classe dérivée ​^ +<code cpp> 
-|les champs ​ou méthodes déclarés ​''​public'' ​dans la classe de base les champs et méthodes ​sont accessibles ​dans la classe dérivée | +class enumerate_characters 
-|les champs ​ou méthodes ​déclarés ''​protected''​ dans la classe de base les champs et méthodes ​sont accessibles ​dans la classe ​dérivée | +
-|les champs ​ou méthodes ​déclarés ​''​private''​ dans la classe de base les champs ​et méthodes ne sont pas accessibles ​dans la classe dérivée ​|+private: 
 +  int mPosition;​ 
 +protected:​ 
 +  int mNumberOfCharacters;​ 
 +  const char* mString; 
 +public: 
 +</​code>​ 
 + 
 +Nous voyons que la classe ''​bidi_enumerate_characters''​ ajoute la fonction ''​previous()''​ à la classe de base
 + 
 +<code cpp> 
 +  int previous() 
 +  { 
 +      return mReversePosition >= 0 ?  
 +        (int)mString[mPosition++] : -1; 
 +  } 
 +</​code>​ 
 + 
 +c'est pour cela qu'on dit qu'​une ​classe dérivée ​est une extension de la classe de base par ce qu'​elle peut ajouter des fonctions et des comportements. ​ 
 + 
 +Ensuite, nous constatons que la classe ''​bidi_enumerate_characters''​ rédéfinit la méthode ''​reset()''​ : 
 + 
 +<code cpp> 
 +  void reset() 
 +  { 
 +      mReversePosition= mNumberOfCharacters;​ 
 +      enumerate_characters()::​reset();​ 
 +  } 
 +</​code>​ 
 + 
 +En effet, lorsque nous appellons la méthode ''​reset()'',​ nous mettons d'​abord le champs ''​mReversePosition'' ​à ''​mNumberOfCharacters''​ et puis ensuite nous appellons la méthode ''​reset()''​ de la classe de base ''​enumerate_characters()::​reset()''​. Nous avons spécialisé le comportement de la fonction ''​reset()''​ par rapport à la fonction ''​reset()''​ de la classe de base. C'est pour cela que les classes dérivées sont aussi appellées classes spécialisées. 
 + 
 +[[cpp:​syntax:​class:​deriving:​creating|Définir une classe dérivée]] 
 + 
 +[[cpp:​syntax:​class:​deriving:​methods|Définir ​champs et méthodes dans une classe dérivée]] 
 + 
 +[[cpp:​syntax:​class:​deriving:​constructor|Définir les constructeurs dans une classe dérivée]] 
 + 
 +[[cpp:​syntax:​class:​deriving:​destructor|Définir ​les destructeurs dans une classe dérivée]] 
 + 
 + 
 +===== Déclarer des champs ​dans une classe dérivée ===== 
 + 
 +Les champs qui sont déclarés ​dans une classe dérivée ne peuvent pas avoir le même nom que les champs dans une des classes de base. 
 + 
 +===== Déclarer des méthodes dans une classe dérivée ===== 
 + 
 +__**Cas 1**: La méthode ​''​method'' ​a un nom différent de celui des méthodes existance ​dans la classe de base.__ 
 + 
 +C'est par exemple le cas de la méthode ''​previous()''​ dans la classe ''​bidi_enumerate_characters''​ : 
 +<code cpp> 
 +  int previous() 
 +  { 
 +      return mReversePosition >= 0 ?  
 +        (int)mString[mPosition++] : -1; 
 +  } 
 +</​code>​ 
 + 
 +Ce sont les règles habituelles de la déclaration des méthodes ​dans les classes. La nouvelle méthode s'​ajoute aux anciennes méthodes. 
 + 
 +__**Cas 2**: La méthode ''​method''​ a le même nom que celui des méthodes existance ​dans la classe ​de base.__ 
 + 
 +C'est par exemple le cas de la méthode ''​reset()''​ dans la classe ''​bidi_enumerate_characters''​ : 
 +<code cpp> 
 +  void reset() 
 +  { 
 +      mPosition = 0; 
 +      enumerate_characters()::​reset();​ 
 +  } 
 +</​code>​ 
 + 
 +**Règle 1**: Si nous définissons une ou plusieurs ​méthodes ​ayant le nom ''​method'' ​et que des méthodes ayant le même nom ont été définies ​dans la classe de baseles méthodes ayant comme nom ''​method''​ sont cachées dans la classe de base.  
 + 
 +<code cpp> 
 +class enumerate_characters 
 +
 +private: 
 +  int mPosition;​ 
 +protected:​ 
 +  int mNumberOfCharacters;​ 
 +  const char* mString; 
 +public: 
 +  enumerate_characters(const char* aString, int theNumberOfCharacters):​ 
 +      mString(aString),​ mNumberOfCharacters(theNumberOfCharacters) {} 
 +   
 +  int next() 
 +  { 
 +      return mPosition < mNumberOfCharacters ?  
 +        (int)mString[mPosition++] : -1; 
 +  } 
 +  void reset() 
 +  { 
 +      mPosition = 0; 
 +  } 
 +
 + 
 +class extended_enumerate_characters:​ enumerate_characters 
 +
 +public: 
 +  extended_enumerate_characters(const char* aString, int theNumberOfCharacters):​ 
 +      enumerate_characters(aString,​ theNumberOfCharacters) {} 
 +   
 +  int next(int lookup) 
 +  { 
 +      mPosition += increment;​ 
 +      if(mPosition >= mNumberOfCharacters) 
 +      { 
 +          mPosition = mNumberOfCharacters;​ 
 +          return (int)-1; 
 +      } 
 +      return (int)mString[mPosition++];​ 
 +  } 
 +
 +</​code>​ 
 + 
 +Dans ce cas, la méthode ''​next(int)''​ va être la seule méthode visible dans la classe ​ ''​extended_enumerate_characters''​. La méthode ''​next()''​ de la classe ''​enumerate_characters''​ mais elle sera masquée ​et sera donc inaccessible. 
 + 
 +**Règle 2**: Il est possible de rendre visible dans la classe dérivée les méthodes ​qui ont été définies dans la classe de base est qui ne prennent ​pas les même arguments que celles définies ​dans la classe dérivée
 + 
 +Si nous voulons rendre la méthode ''​next()''​ visible, il faudra ajouter à la classe ''​extended_enumerate_characters''​ la directive : ''​using enumerate_characters::​next''​ pour indiquer que les méthodes ayant pour nom ''​next''​ et étant définie dans la classe de base sont aussi visible dans la classe dérivée. 
 +<code cpp> 
 +class extended_enumerate_characters:​ enumerate_characters 
 +
 +public: 
 +  extended_enumerate_characters(const char* aString, int theNumberOfCharacters):​ 
 +      enumerate_characters(aString,​ theNumberOfCharacters) {} 
 + 
 +  using enumerate_characters::​next;​ 
 +  int next(int lookup) 
 +  { 
 +      mPosition += increment;​ 
 +      if(mPosition >= mNumberOfCharacters) 
 +      { 
 +          mPosition = mNumberOfCharacters;​ 
 +          return (int)-1; 
 +      } 
 +      return (int)mString[mPosition++];​ 
 +  } 
 +
 +</​code>​ 
 + 
 +Dans la classe ''​extended_enumerate_characters'',​ les deux méthodes ''​enumerate_characters::​next()''​ et  
 +''​extended_enumerate_characters::​next(int)''​ sont accessibles.  
 + 
 +<code cpp> 
 +    extended_enumerate_characters enumerator("​abcdefg"​);​ 
 +    std::cout << enumerator.next(2);​ 
 +    std::cout << enumerator.next();​ 
 +</​code>​
  
-Cependantil faut aussi s'​intéresser à l'​accesibilité des méthodes en dehors de la classe ​dérivée. C'est ici qu'intervient les attributs d'accessibilité que l'on place devant le type de la classe dont hérite qui peuvent être ''​public''​''​protected'' ​ou ''​private''​.+Par contredans la classe ''​bidi_enumerate_characters''​, ajouter ​''​using enumerate_characters::​reset'' ​ne sert à rien parce que la fonction ​''​reset()'' ​dans la classe dérivée à la [[cpp::​syntax::​functions::​overload|même signature]] que la fonction ​''​reset'' ​dans la classe de base.
  
-^ Attribut d'​héritage ^ Accessibilité en dehors de la classe ^ Accessibilité dans une classe dérivant de ''​DerivingClass''​ ^ 
-|DerivingClass:​ public BaseClass| Les méthodes et champs ''​public''​ de ''​BaseClass''​ sont accessibles. | 
-Les méthodes et champs ''​public''​ ou ''​protected''​ de ''​BaseClass''​ sont accesibiles à la classe dérivée. | 
in204/cpp/syntax/class/deriving.1569270284.txt.gz · Last modified: 2019/09/23 20:24 by bmonsuez