Menu
Coddy logo textTech

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 : 50

C’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.

challenge icon

Défi

Facile

Construisons 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 structure Vehicle avec deux fields : speed (un entier pour la vitesse current) et max_speed (un entier pour la vitesse maximale du véhicule). Puis Define une structure Motorcycle qui intègre Vehicle comme son premier member et ajoute un champ has_sidecar (un entier, où 1 signifie oui et 0 signifie non). Déclarez deux fonctions : boost, qui prend un Vehicle* et un amount pour Increase la vitesse, et print_motorcycle, qui prend un Motorcycle*.
  • vehicle.c : Implement les deux fonctions. Votre fonction boost doit 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 fonction print_motorcycle doit afficher all les informations de la motorcycle, y compris les données de son véhicule intégré.
  • main.c : Create une Motorcycle et initialize tous ses fields. Puis démontrez l’upcasting en appelant la fonction boost : effectuez un cast de votre Motorcycle* en Vehicle* 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: Yes

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;
}
quiz iconTestez-vous

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

Entraînez-vous par vous-même : Compilateur C en ligne