Menu
CoddyTech

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

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

challenge icon

Défi

Facile

Construisons 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 structure Vehicle avec deux champs : speed (un entier correspondant à la vitesse actuelle) et max_speed (un entier correspondant à la vitesse maximale du véhicule). Définis ensuite une structure Motorcycle qui intègre Vehicle comme premier membre et ajoute un champ has_sidecar (un entier, où 1 signifie oui et 0 signifie non). Déclare deux fonctions : boost, qui prend un Vehicle* et une quantité d’augmentation de la vitesse, et print_motorcycle, qui prend un Motorcycle*.
  • vehicle.c : implémente les deux fonctions. Ta fonction boost doit 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 sur max_speed. Ta fonction print_motorcycle doit afficher toutes les informations de la moto, y compris les données de son véhicule intégré.
  • main.c : crée une Motorcycle et initialise tous ses champs. Montre ensuite la conversion ascendante en appelant la fonction boost : convertis ton Motorcycle* en Vehicle* 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: Yes

Où 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;
}
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