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érons une structure de base Vehicle et une Car qui la contient :
typedef struct {
int speed;
} Vehicle;
typedef struct {
Vehicle vehicle; // Base en tant que premier membre
int doors;
} Car;Imaginez 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 transmettre 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 ce qu’on appelle une conversion ascendante : nous passons « vers le haut », d’un type spécifique à un type général. La fonction accelerate ne sait pas qu’elle travaille avec un Car ; elle ne voit qu’un Vehicle. Cela vous permet d’écrire du code réutilisable qui fonctionne sur 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 démontre l’upcasting en action. Vous allez 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 à un cast de pointeur.
L’intérêt de l’upcasting est que vous pouvez écrire des fonctions pour le type de base, et qu’elles fonctionneront parfaitement avec tout type dérivé qui l’intègre. Votre motorcycle « est un » véhicule, donc toute fonction qui attend un Vehicle* devrait pouvoir le traiter.
Vous organiserez votre code sur trois fichiers :
vehicle.h: Define votre hiérarchie de structures avec des protections contre les inclusions multiples. Create une structureVehicleavec deux fields :speed(un entier pour la vitesse current) etmax_speed(un entier pour la vitesse maximale du véhicule). Puis Define une structureMotorcyclequi intègreVehiclecomme son premier member et ajoute un champhas_sidecar(un entier, où 1 signifie oui et 0 signifie non). Déclarez deux fonctions :boost, qui prend unVehicle*et un amount pour Increase la vitesse, etprint_motorcycle, qui prend unMotorcycle*.vehicle.c: Implement les deux fonctions. Votre fonctionboostdoit augmenter la vitesse du véhicule de l’amount donné, mais la limiter àmax_speed: si la nouvelle vitesse devait exceed le maximum, définissez-la plutôt àmax_speed. Votre fonctionprint_motorcycledoit afficher all les informations de la motorcycle, y compris les données de son véhicule intégré.main.c: Create uneMotorcycleet initialize tous ses fields. Puis démontrez l’upcasting en appelant la fonctionboost: effectuez un cast de votreMotorcycle*enVehicle*pour le pass à cette fonction générique. Après l’augmentation, affichez les informations de la motorcycle pour voir le résultat.
Vous recevrez quatre entrées : la initial speed de la motorcycle, sa max speed, si elle has a sidecar (1 ou 0), et l’boost amount.
Votre sortie devrait ressembler à ceci :
Speed: 75
Max Speed: 120
Sidecar: YesOù 75 est la vitesse après l’augmentation (initiale 50 + boost 25), 120 est la vitesse maximale, et Yes ou No indique si la motorcycle has a sidecar. Si l’augmentation devait faire dépasser max_speed à la vitesse, celle-ci devrait être limitée à max_speed.
L’apprentissage clé ici est que boost ne sait rien des motorcycles. Il fonctionne uniquement avec Vehicle. Pourtant, grâce à l’upcasting, votre motorcycle peut utiliser cette fonction générique pour modifier ses données de véhicule intégrées.
Essayez vous-même
#include <stdio.h>
#include "vehicle.h"
int main() {
int initial_speed, max_speed, has_sidecar, boost_amount;
// Lire les entrées
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 embarque Vehicle comme son premier membre
// TODO: Démontrer l'upcasting en appelant boost
// Castez votre Motorcycle* en Vehicle* pour le passer à la fonction boost
// TODO: Afficher les informations de la motorcycle
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