C++ Polymorphisme avec exemple
Qu'est-ce que le polymorphisme dans C++?
In C++, le polymorphisme amène une fonction membre à se comporter différemment en fonction de l'objet qui l'appelle/l'invoque. Le polymorphisme est un mot grec qui signifie avoir plusieurs formes. Cela se produit lorsque vous avez une hiérarchie de classes liées par héritage.
Par exemple, supposons que nous ayons la fonction makeSound(). Lorsqu'un chat appelle cette fonction, il produira le son de miaulement. Lorsqu’une vache invoque la même fonction, elle émettra le son du meuh.
Même si nous avons une fonction, elle se comporte différemment selon les circonstances. La fonction a plusieurs formes ; nous avons donc atteint le polymorphisme.
Types de polymorphisme
C++ prend en charge deux types de polymorphisme :
- Polymorphisme au moment de la compilation, et
- Polymorphisme d'exécution.
Polymorphisme au moment de la compilation
Vous invoquez les fonctions surchargées en faisant correspondre le nombre et le type d'arguments. Les informations sont présentes au moment de la compilation. Cela signifie que C++ le compilateur sélectionnera la bonne fonction au moment de la compilation.
Le polymorphisme au moment de la compilation est obtenu grâce à la surcharge de fonctions et à la surcharge d'opérateurs.
Surcharge de fonction
La surcharge de fonctions se produit lorsque nous avons de nombreuses fonctions avec des noms similaires mais des arguments différents. Les arguments peuvent différer en termes de nombre ou de type.
Exemple 1
#include <iostream> using namespace std; void test(int i) { cout << " The int is " << i << endl; } void test(double f) { cout << " The float is " << f << endl; } void test(char const *ch) { cout << " The char* is " << ch << endl; } int main() { test(5); test(5.5); test("five"); return 0; }
Sortie :
Voici une capture d'écran du code :
Explication du code :
- Incluez le fichier d'en-tête iostream dans notre code. Nous pourrons utiliser ses fonctions.
- Incluez l'espace de noms std dans notre code. Nous pourrons utiliser ses classes sans l'appeler.
- Créez une fonction nommée test qui prend un paramètre entier i. Le { marque le début du corps du test fonctionnel.
- Instruction à exécuter si le test de fonction ci-dessus est invoqué/appelé.
- Fin du corps du test fonctionnel ci-dessus.
- Créez une fonction nommée test qui prend un paramètre float f. Le { marque le début du corps du test fonctionnel.
- Instruction à exécuter si le test de fonction ci-dessus est invoqué/appelé.
- Fin du corps du test fonctionnel ci-dessus.
- Créez une fonction nommée test qui prend un paramètre de caractère ch. Le { marque le début du corps du test fonctionnel.
- Instruction à exécuter si le test de fonction ci-dessus est invoqué/appelé.
- Fin du corps du test fonctionnel ci-dessus.
- Appelez la fonction main(). Le { marque le début du corps de la fonction.
- Appelez la fonction test et passez-lui 5 comme valeur de l'argument. Cela appelle la fonction de test qui accepte un argument entier, c'est-à-dire la première fonction de test.
- Appelez la fonction test et passez-lui 5.5 comme valeur de l'argument. Cela invoquera la fonction de test qui accepte un argument float, c'est-à-dire la deuxième fonction de test.
- Appelez la fonction test et transmettez-lui cinq comme valeur de l'argument. Cela invoquera la fonction de test qui accepte un argument de caractère, c'est-à-dire la troisième fonction de test.
- Le programme doit renvoyer une valeur s'il s'exécute correctement.
- La fin du corps de la fonction main().
Nous avons trois fonctions portant le même nom mais des types d’arguments différents. Nous avons atteint le polymorphisme.
OperaTor Surcharge
In Operator Surcharge, nous définissons un nouveau sens pour un C++ opérateur. Cela modifie également le fonctionnement de l'opérateur. Par exemple, nous pouvons définir l'opérateur + pour concaténer deux chaînes. Nous le connaissons comme l'opérateur d'addition pour ajouter des valeurs numériques. D'après notre définition, lorsqu'il est placé entre des entiers, il les additionne. Lorsqu'il est placé entre des chaînes, il les concatène.
Exemple 2
#include<iostream> using namespace std; class ComplexNum { private: int real, over; public: ComplexNum(int rl = 0, int ov = 0) { real = rl; over = ov; } ComplexNum operator + (ComplexNum const &obj) { ComplexNum result; result.real = real + obj.real; result.over = over + obj.over; return result; } void print() { cout << real << " + i" << over << endl; } }; int main() { ComplexNum c1(10, 2), c2(3, 7); ComplexNum c3 = c1+c2; c3.print(); }
Sortie :
Voici une capture d'écran du code :
Explication du code :
- Incluez le fichier d'en-tête iostream dans notre programme afin d'utiliser ses fonctions.
- Incluez l'espace de noms std dans notre programme afin d'utiliser ses classes sans l'appeler.
- Créez une classe nommée ComplexNum. Le { marque le début du corps de la classe.
- Utilisez le modificateur d'accès privé pour marquer les variables comme privées, ce qui signifie qu'elles ne sont accessibles qu'à partir de la classe.
- Définissez deux variables entières, réelles et supérieures.
- Utilisez le modificateur d'accès public pour marquer le constructeur comme public, ce qui signifie qu'il sera accessible même depuis l'extérieur du classe.
- Créez le constructeur de classe et initialisez les variables.
- Initialisez la valeur de la variable real.
- Initialisez la valeur de la variable over.
- Fin du corps constructeur.
- Nous devons remplacer la signification de l’opérateur +.
- Créez le résultat du type de données de type ComplexNum.
- Utilisez l'opérateur + avec les nombres complexes. Cette ligne ajoutera la partie réelle d'un nombre à la partie réelle d'un autre nombre.
- Utilisez l'opérateur + avec les nombres complexes. Cette ligne ajoutera la partie imaginaire d'un nombre à la partie imaginaire d'un autre nombre.
- Le programme renverra la valeur du résultat variable en cas d'exécution réussie.
- Fin de la définition du nouveau sens de l'opérateur +, c'est-à-dire la surcharge.
- Appelez la méthode print().
- Imprimez le nouveau numéro complexe après ajout sur la console.
- Fin du corps de la fonction print().
- Fin du corps de la classe ComplexNum.
- Appelez la fonction main().
- Transmettez les valeurs des pièces réelles et complexes à ajouter. La première partie de c1 sera ajoutée à la première partie de c2, soit 10+3. La deuxième partie de c1 sera ajoutée à la deuxième partie de c, soit 2+7.
- Effectuez une opération en utilisant l'opérateur + surchargé et en stockant le résultat dans la variable c3.
- Imprimez la valeur de la variable c3 sur la console.
- Fin du corps de la fonction main().
Polymorphisme d'exécution
Cela se produit lorsque la méthode d'un objet est invoquée/appelée pendant l'exécution plutôt que pendant la compilation. Le polymorphisme d'exécution est obtenu grâce au remplacement de fonctions. La fonction à appeler/invoquée est établie pendant l'exécution.
Remplacement de fonction
Le remplacement de fonction se produit lorsqu'une fonction de la classe de base reçoit une nouvelle définition dans une classe dérivée. À ce moment-là, nous pouvons dire que la fonction de base a été remplacée.
Par exemple :
#include <iostream> using namespace std; class Mammal { public: void eat() { cout << "Mammals eat..."; } }; class Cow: public Mammal { public: void eat() { cout << "Cows eat grass..."; } }; int main(void) { Cow c = Cow(); c.eat(); return 0; }
Sortie :
Voici une capture d'écran du code :
Explication du code :
- Importez le fichier d'en-tête iostream dans notre programme pour utiliser ses fonctions.
- Incluez l'espace de noms std dans notre programme afin d'utiliser ses classes sans l'appeler.
- Créez une classe nommée Mammifère. Le { marque le début du corps de la classe.
- Utilisez le modificateur d'accès public pour définir la fonction que nous sommes sur le point de créer comme accessible publiquement. Il sera accessible depuis l'extérieur de cette classe.
- Créez une fonction publique nommée manger. Le { marque le début du corps de la fonction.
- Affiche l'instruction ajoutée à la fonction cout lorsque la fonction eat() est invoquée.
- La fin du corps de la fonction eat().
- Fin du corps de la classe Mammifère.
- Créez une classe nommée Cow qui hérite de la classe Mammal. La vache est la classe dérivée, tandis que les mammifères sont la classe de base. Le { marque le début de cette classe.
- Utilisez le modificateur d'accès public pour marquer la fonction que nous sommes sur le point de créer comme accessible publiquement. Il sera accessible depuis l'extérieur de cette classe.
- Remplacez la fonction eat() qui a été définie dans la classe de base. Le { marque le début du corps de la fonction.
- L'instruction à imprimer sur la console lorsque cette fonction est invoquée.
- Fin du corps de la fonction eat().
- Fin du corps de la classe Vache.
- Appelez la fonction main(). Le { marque le début du corps de cette fonction.
- Créez une instance de la classe Cow et donnez-lui le nom c.
- Appelez la fonction eat() définie dans la classe Cow.
- Le programme doit renvoyer une valeur une fois terminé.
- Fin de la fonction main().
C++ Fonction virtuelle
Une fonction virtuelle est une autre façon d'implémenter le polymorphisme d'exécution dans C++. Il s'agit d'une fonction spéciale définie dans une classe de base et redéfinie dans la classe dérivée. Pour déclarer une fonction virtuelle, vous devez utiliser le mot-clé virtual. Le mot-clé doit précéder la déclaration de la fonction dans la classe de base.
Si une classe de fonctions virtuelles est héritée, la classe virtuelle redéfinit la fonction virtuelle en fonction de ses besoins. Par exemple:
#include <iostream> using namespace std; class ClassA { public: virtual void show() { cout << "The show() function in base class invoked..." << endl; } }; class ClassB :public ClassA { public: void show() { cout << "The show() function in derived class invoked..."; } }; int main() { ClassA* a; ClassB b; a = &b; a->show(); }
Sortie :
Voici une capture d'écran du code :
Explication du code :
- Incluez le fichier d'en-tête iostream dans le code pour utiliser ses fonctions.
- Incluez l'espace de noms std dans notre code pour utiliser ses classes sans l'appeler.
- Créez une classe nommée ClassA.
- Utilisez le modificateur d'accès public pour marquer un membre de la classe comme accessible publiquement.
- Créez une fonction virtuelle nommée show(). Ce sera une fonction publique.
- Le texte à imprimer lorsque le show() invoqué est invoqué. La fin est un C++ mot-clé, qui signifie ligne de fin. Il déplace le curseur de la souris vers la ligne suivante.
- Fin du corps de la fonction virtuelle show().
- Fin du corps de la classe ClassA.
- Création d'une nouvelle classe nommée ClassB qui hérite de la classe ClassA. ClassA devient la classe de base tandis que ClassB devient la classe dérivée.
- Utilisez le modificateur d'accès public pour marquer un membre de la classe comme accessible publiquement.
- Redéfinissez la fonction virtuelle show() dérivée dans la classe de base.
- Le texte à imprimer sur la console lorsque la fonction show() définie dans la classe dérivée est invoquée.
- Fin du corps de la fonction show().
- Fin du corps de la classe dérivée, ClassB.
- Appelez la fonction main(). La logique du programme doit être ajoutée dans son corps.
- Créez une variable de pointeur nommée a. Il pointe vers la classe nommée ClassA.
- Créez une instance de la classe nommée ClassB. L'instance reçoit le nom b.
- Affectez les valeurs stockées à l’adresse b dans la variable a.
- Invoquez la fonction show() définie dans la classe dérivée. La liaison tardive a été mise en œuvre.
- Fin du corps de la fonction main().
Polymorphisme au moment de la compilation vs. Polymorphisme d'exécution
Voici les principales différences entre les deux :
Polymorphisme à la compilation | Polymorphisme d'exécution |
---|---|
On l'appelle également liaison précoce ou polymorphisme statique. | On l'appelle également liaison tardive/dynamique ou polymorphisme dynamique. |
La méthode est appelée/invoquée pendant la compilation | La méthode est appelée/invoquée pendant l'exécution |
Implémenté via une surcharge de fonctions et une surcharge d'opérateurs | Implémenté via le remplacement de méthode et les fonctions virtuelles |
Exemple, surcharge de méthode. De nombreuses méthodes peuvent avoir des noms similaires mais un nombre ou des types d'arguments différents | Exemple, substitution de méthode. De nombreuses méthodes peuvent avoir un nom similaire et le même prototype. |
Exécution plus rapide puisque la découverte des méthodes se fait pendant la compilation | Exécution plus lente puisque le découvreur de méthodes est effectué pendant l’exécution. |
Less la flexibilité pour la résolution de problèmes est fournie puisque tout est connu au moment de la compilation. | Une grande flexibilité est offerte pour résoudre des problèmes complexes puisque les méthodes sont découvertes pendant l'exécution. |
Résumé
- Le polymorphisme signifie avoir plusieurs formes.
- Cela se produit lorsqu’il existe une hiérarchie de classes liées par héritage.
- Avec le polymorphisme, une fonction peut se comporter différemment en fonction de l'objet qui l'invoque/l'appelle.
- Dans le polymorphisme au moment de la compilation, la fonction à appeler est établie au moment de la compilation.
- Dans le polymorphisme d'exécution, la fonction à appeler est établie pendant l'exécution.
- Le polymorphisme au moment de la compilation est déterminé par la surcharge de fonctions et la surcharge d'opérateurs.
- Dans la surcharge de fonctions, il existe de nombreuses fonctions avec des noms similaires mais des arguments différents.
- Les paramètres peuvent différer en nombre ou en type.
- Dans la surcharge d'opérateurs, une nouvelle signification est définie pour C++ opérateurs.
- Le polymorphisme d'exécution est obtenu grâce au remplacement de fonctions.
- Lors du remplacement de fonction, une classe dérivée donne une nouvelle définition à une fonction définie dans la classe de base.