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:19]
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 base. Ainsinous 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''​. Attention, les 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''​ : 
 + 
 +<code cpp> 
 +class enumerate_characters 
 +
 +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 classesLa 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* aStringint 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>​
  
-^ Déclaration ​dans la classe ​de base ^ Accesibilité dans la classe dérivée ^ +Par contre, ​dans 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.
-|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 | +
-|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 |+
  
in204/cpp/syntax/class/deriving.1569269982.txt.gz · Last modified: 2019/09/23 20:19 by bmonsuez