This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
in204:cpp:syntax:class:deriving [2021/03/28 10:08] bmonsuez |
in204:cpp:syntax:class:deriving [2022/11/18 10:51] (current) |
||
---|---|---|---|
Line 120: | Line 120: | ||
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. | 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. | ||
- | ===== Définition d'une classe dérivée ==== | + | [[cpp:syntax:class:deriving:creating|Définir une classe dérivée]] |
- | 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. | + | [[cpp:syntax:class:deriving:methods|Définir champs et méthodes dans une classe dérivée]] |
- | 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. | + | [[cpp:syntax:class:deriving:constructor|Définir les constructeurs dans une classe dérivée]] |
- | ===== Déclaration d'une classe dérivée ==== | + | [[cpp:syntax:class:deriving:destructor|Définir les destructeurs dans une classe dérivée]] |
- | La syntaxe pour déclarer une classe comme héritant d'une classe de base est la suivante : | ||
- | <code cpp> | ||
- | class DerivingClass: public BaseClass | + | ===== 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> | </code> | ||
- | ==== Accessibilité des méthodes et des champs d'une classe de base ==== | + | 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. |
- | 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''. Cependant, il faut faire attention, présent ne veut pas dire qu'ils sont accessibles dans la classe de base. Ainsi, nous avons les règles d'accessibilité suivantes pour les méthodes et les champs définis dans la classe de base. | + | __**Cas 2**: La méthode ''method'' a le même nom que celui des méthodes existance dans la classe de base.__ |
- | ^ Déclaration dans la classe de base ^ Accesibilité dans la classe dérivée ^ | + | C'est par exemple le cas de la méthode ''reset()'' dans la classe ''bidi_enumerate_characters'' : |
- | |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 | | + | <code cpp> |
- | |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 | | + | void reset() |
- | |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 | | + | { |
+ | mPosition = 0; | ||
+ | enumerate_characters()::reset(); | ||
+ | } | ||
+ | </code> | ||
- | Cependant, il 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''. | + | **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 base, les méthodes ayant comme nom ''method'' sont cachées dans la classe de base. |
- | ^ Attribut d'héritage ^ Accessibilité en dehors de la classe ^ Accessibilité dans une classe dérivant de ''DerivingClass'' ^ | + | <code cpp> |
- | |''DerivingClass: public BaseClass''| Les méthodes et champs ''public'' de ''BaseClass'' sont accessibles. | Les méthodes et champs ''public'' ou ''protected'' de ''BaseClass'' sont accessibles à la classe dérivée. | | + | class enumerate_characters |
- | |''DerivingClass: private BaseClass''| Aucune méthode ou champs de ''BaseClass'' ne sont accessibles. | Aucune méthode ou champs de ''BaseClass'' ne sont accessibles à la classe dérivée. | | + | { |
- | |''DerivingClass: protected BaseClass''| Aucune méthode ou champs de ''BaseClass'' sont accessibles. | Les méthodes et champs ''public'' ou ''protected'' de ''BaseClass'' sont accessibles à la classe dérivée. | | + | 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> | ||
- | ===== Déclarer des champs dans une classe dérivée ===== | + | 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. |
- | 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. | + | **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. |
- | ===== Déclarer des méthodes dans une 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) {} | ||
- | __**Cas 1**: La méthode ''method'' a un nom différent de celui des méthodes existance dans la classe de base.__ | + | using enumerate_characters::next; |
+ | int next(int lookup) | ||
+ | { | ||
+ | mPosition += increment; | ||
+ | if(mPosition >= mNumberOfCharacters) | ||
+ | { | ||
+ | mPosition = mNumberOfCharacters; | ||
+ | return (int)-1; | ||
+ | } | ||
+ | return (int)mString[mPosition++]; | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
- | Cette | + | 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> | ||
+ | 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. | ||