Menu
Coddy logo textTech

Upcasting

Fa parte della sezione Programmazione orientata agli oggetti del percorso C di Coddy. Lezione 31 di 61.

L'upcasting consiste nel trattare un tipo specifico (derivato) come il suo tipo più generale (base). Nel modello di composizione di C, significa passare a una funzione che si aspetta il tipo base un puntatore a una struct che incorpora un tipo base.

Considera una struct di base Vehicle e una Car che la contiene:

typedef struct {
    int speed;
} Vehicle;

typedef struct {
    Vehicle vehicle;  // Base come primo membro
    int doors;
} Car;

Ora immagina una funzione generica che funziona con qualsiasi veicolo:

void accelerate(Vehicle* v, int amount) {
    v->speed += amount;
}

Grazie alla regola del primo membro, possiamo passare un Car* a questa funzione convertendolo in Vehicle*:

Car my_car = {{0}, 4};  // speed=0, doors=4
accelerate((Vehicle*)&my_car, 50);
printf("Speed: %d\n", my_car.vehicle.speed);  // Output: 50

Questo è l’upcasting: ci stiamo spostando “verso l’alto”, da un tipo specifico a uno più generale. La funzione accelerate non sa di lavorare con una Car; vede solo un Vehicle. Questo ti permette di scrivere codice riutilizzabile che opera sul tipo base e accetta qualsiasi tipo derivato che lo incorpori.

challenge icon

Sfida

Facile

Costruiamo un semplice sistema di trasporti che mostra l'upcasting in azione. Creerai un tipo base Vehicle e un tipo più specifico Motorcycle, poi mostrerai come una funzione generica possa lavorare con entrambi tramite il cast dei puntatori.

Il vantaggio dell'upcasting è che puoi scrivere funzioni per il tipo base, e funzioneranno senza problemi con qualsiasi tipo derivato che lo includa. La tua motocicletta «è un» veicolo, quindi qualsiasi funzione che si aspetta un Vehicle* dovrebbe poterla elaborare.

Organizzerai il codice in tre file:

  • vehicle.h: Definisci la gerarchia di struct con le protezioni contro le inclusioni multiple. Crea una struct Vehicle con due campi: speed (un intero che indica la velocità attuale) e max_speed (un intero che indica la velocità massima del veicolo). Poi definisci una struct Motorcycle che include Vehicle come primo membro e aggiunge un campo has_sidecar (un intero, dove 1 significa sì e 0 significa no). Dichiara due funzioni: boost, che accetta un Vehicle* e una quantità per aumentare la velocità, e print_motorcycle, che accetta un Motorcycle*.
  • vehicle.c: Implementa entrambe le funzioni. La funzione boost deve aumentare la velocità del veicolo della quantità specificata, ma limitarla a max_speed: se la nuova velocità supererebbe il massimo, impostala invece a max_speed. La funzione print_motorcycle deve mostrare tutte le informazioni sulla motocicletta, compresi i dati del veicolo incluso.
  • main.c: Crea una Motorcycle e inizializza tutti i suoi campi. Poi mostra l'upcasting chiamando la funzione boost: esegui il cast del tuo Motorcycle* a Vehicle* per passarlo a questa funzione generica. Dopo aver aumentato la velocità, stampa le informazioni sulla motocicletta per vedere il risultato.

Riceverai quattro input: la velocità iniziale della motocicletta, la sua velocità massima, se ha un sidecar (1 o 0) e la quantità dell'aumento.

L'output dovrebbe essere simile a questo:

Speed: 75
Max Speed: 120
Sidecar: Yes

Dove 75 è la velocità dopo l'aumento (iniziale 50 + aumento 25), 120 è la velocità massima e Yes oppure No indica se la motocicletta ha un sidecar. Se l'aumento portasse la velocità oltre max_speed, la velocità dovrebbe essere limitata a max_speed.

Il concetto fondamentale da imparare è che boost non sa nulla delle motociclette. Lavora solo con Vehicle. Tuttavia, grazie all'upcasting, la tua motocicletta può usare questa funzione generica per modificare i dati del veicolo incluso.

Provalo tu

#include <stdio.h>
#include "vehicle.h"

int main() {
    int initial_speed, max_speed, has_sidecar, boost_amount;
    
    // Leggi i dati in input
    scanf("%d", &initial_speed);
    scanf("%d", &max_speed);
    scanf("%d", &has_sidecar);
    scanf("%d", &boost_amount);
    
    // TODO: Crea una Motorcycle e inizializza tutti i suoi campi
    // Ricorda: Motorcycle incorpora Vehicle come primo membro
    
    // TODO: Dimostra l'upcasting chiamando boost
    // Converti Motorcycle* in Vehicle* per passarlo alla funzione boost
    
    // TODO: Stampa le informazioni della motocicletta
    
    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C online