Upcasting
Fait partie de la section Programmation Orientée Objet du Journey C de Coddy. Leçon 31 sur 61.
La conversion ascendante consiste à traiter un type spécifique (dérivé) comme son type plus général (de base). Dans le modèle de composition de C, cela signifie transmettre à une fonction qui attend le type de base un pointeur vers une structure qui intègre un type de base.
Considérez une structure de base Vehicle et une structure Car qui la contient :
typedef struct {
int speed;
} Vehicle;
typedef struct {
Vehicle vehicle; // Base comme premier membre
int doors;
} Car;Imagine maintenant une fonction générique qui fonctionne avec n’importe quel véhicule :
void accelerate(Vehicle* v, int amount) {
v->speed += amount;
}Grâce à la règle du premier membre, nous pouvons passer un Car* à cette fonction en le convertissant en Vehicle* :
Car my_car = {{0}, 4}; // speed=0, doors=4
accelerate((Vehicle*)&my_car, 50);
printf("Speed: %d\n", my_car.vehicle.speed); // Sortie : 50C'est une conversion vers le haut : on passe d'un type spécifique à un type général. La fonction accelerate ne sait pas qu'elle travaille avec une Car ; elle ne voit qu'un Vehicle. Cela te permet d'écrire du code réutilisable qui fonctionne avec le type de base tout en acceptant n'importe quel type dérivé qui l'intègre.
Défi
FacileConstruisons un système de transport simple qui montre la conversion ascendante en action. Tu vas créer un type de base Vehicle et un type plus spécifique Motorcycle, puis montrer comment une fonction générique peut fonctionner avec les deux grâce à une conversion de pointeur.
L’avantage de la conversion ascendante est que tu peux écrire des fonctions pour le type de base, et qu’elles fonctionneront parfaitement avec tout type dérivé qui l’intègre. Ta moto « est un » véhicule : toute fonction qui attend un Vehicle* devrait donc pouvoir la traiter.
Tu vas organiser ton code dans trois fichiers :
vehicle.h: définis ta hiérarchie de structures avec des protections contre les inclusions multiples. Crée une structureVehicleavec deux champs :speed(un entier correspondant à la vitesse actuelle) etmax_speed(un entier correspondant à la vitesse maximale du véhicule). Définis ensuite une structureMotorcyclequi intègreVehiclecomme premier membre et ajoute un champhas_sidecar(un entier, où 1 signifie oui et 0 signifie non). Déclare deux fonctions :boost, qui prend unVehicle*et une quantité d’augmentation de la vitesse, etprint_motorcycle, qui prend unMotorcycle*.vehicle.c: implémente les deux fonctions. Ta fonctionboostdoit augmenter la vitesse du véhicule de la quantité indiquée, mais la plafonner àmax_speed: si la nouvelle vitesse dépasse la vitesse maximale, définis-la plutôt surmax_speed. Ta fonctionprint_motorcycledoit afficher toutes les informations de la moto, y compris les données de son véhicule intégré.main.c: crée uneMotorcycleet initialise tous ses champs. Montre ensuite la conversion ascendante en appelant la fonctionboost: convertis tonMotorcycle*enVehicle*pour le transmettre à cette fonction générique. Après l’augmentation de la vitesse, affiche les informations de la moto pour voir le résultat.
Tu recevras quatre entrées : la vitesse initiale de la moto, sa vitesse maximale, si elle a un side-car (1 ou 0), et la quantité d’augmentation.
Ta sortie doit ressembler à ceci :
Speed: 75
Max Speed: 120
Sidecar: YesOù 75 est la vitesse après l’augmentation (vitesse initiale 50 + augmentation 25), 120 est la vitesse maximale, et Yes ou No indique si la moto a un side-car. Si l’augmentation faisait dépasser la vitesse maximale à la moto, la vitesse devrait être plafonnée à max_speed.
La leçon essentielle à retenir est que boost ne sait rien des motos. Cette fonction ne fonctionne qu’avec Vehicle. Pourtant, grâce à la conversion ascendante, ta moto peut utiliser cette fonction générique pour modifier les données de son véhicule intégré.
Essayez vous-même
#include <stdio.h>
#include "vehicle.h"
int main() {
int initial_speed, max_speed, has_sidecar, boost_amount;
// Lire les données d’entrée
scanf("%d", &initial_speed);
scanf("%d", &max_speed);
scanf("%d", &has_sidecar);
scanf("%d", &boost_amount);
// TODO: Créer une Motorcycle et initialiser tous ses champs
// Rappel : Motorcycle contient Vehicle comme premier membre
// TODO: Montrer la conversion vers un type de base en appelant boost
// Convertir votre Motorcycle* en Vehicle* pour le passer à la fonction boost
// TODO: Afficher les informations de la moto
return 0;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Bases de la programmation modulaire
Fichiers d'en-têteGardes d'inclusionFichiers sourcesFonctions statiquesRécapitulatif : Calculatrice modulaire4Encapsulation
Concept des pointeurs opaquesDéfinir des structures opaquesGetters et settersValidation dans les settersRécapitulatif : La boîte secrète2Objets et méthodes
Structs comme objetsLe pointeur 'Self'Rigueur du mot-clé constPointeur vs ValeurMéthodes utilitairesRécapitulatif : Point Manager5Projet : Compte bancaire simple
Configuration du projetImplémentation du compte8Polymorphisme
Pointeurs de fonctions dans les structuresSimulation de méthodesLe concept d'interfaceImplémentation d'interfacesItération polymorphiqueRécapitulatif : Greeter11Patrons de conception en C
Patron SingletonPatron FabriquePatron ItérateurRécapitulatif : Logger Factory3Cycle de vie des objets
Pattern de constructeurPattern de destructeurInitialisation sur la pileCopie profondeRécapitulatif : String Wrapper6Héritage par composition
Imbrication de structLa règle du premier membreAccès aux membres parentsUpcastingRécapitulatif : Hiérarchie des formes9Projet : Dessinateur de formes
Aperçu du projetImplémentation du cercleImplémentation du rectangleUtilisation polymorpheConteneur de formesEntraînez-vous par vous-même : Compilateur C en ligne