Upcasting
Fa parte della sezione Programmazione orientata agli oggetti del percorso C di Coddy. Lezione 31 di 61.
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 struttura 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: 50Questo è un upcasting: stiamo passando «verso l’alto» da un tipo specifico a uno generale. La funzione accelerate non sa di lavorare con una Car; vede solo una Vehicle. Questo ti permette di scrivere codice riutilizzabile che opera sul tipo base e accetta qualsiasi tipo derivato che lo incorpori.
Sfida
FacileCostruiamo un semplice sistema di trasporto che mostri in pratica il upcasting. Creerai un tipo base Vehicle e un tipo più specifico Motorcycle, poi vedrai come una funzione generica può lavorare con entrambi tramite il casting dei puntatori.
Il vantaggio del upcasting è che puoi scrivere funzioni per il tipo base, che funzioneranno senza problemi con qualsiasi tipo derivato che lo incorpori. 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 di inclusione. Crea una structVehiclecon due campi:speed(un intero che indica la velocità attuale) emax_speed(un intero che indica la velocità massima del veicolo). Poi definisci una structMotorcycleche incorporaVehiclecome primo membro e aggiunge un campohas_sidecar(un intero, dove 1 significa sì e 0 significa no). Dichiara due funzioni:boost, che accetta unVehicle*e una quantità con cui aumentare la velocità, eprint_motorcycle, che accetta unMotorcycle*.vehicle.c: Implementa entrambe le funzioni. La funzioneboostdeve aumentare la velocità del veicolo della quantità specificata, ma limitarla amax_speed: se la nuova velocità supera il massimo, impostala invece amax_speed. La funzioneprint_motorcycledeve visualizzare tutte le informazioni della motocicletta, inclusi i dati del veicolo incorporato.main.c: Crea unaMotorcyclee inizializza tutti i suoi campi. Poi mostra il upcasting chiamando la funzioneboost: esegui il cast del tuoMotorcycle*aVehicle*per passarlo a questa funzione generica. Dopo aver aumentato la velocità, stampa le informazioni della 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: YesDove 75 è la velocità dopo l'aumento (iniziale 50 + aumento 25), 120 è la velocità massima e Yes o No indica se la motocicletta ha un sidecar. Se l'aumento porta la velocità oltre max_speed, la velocità deve essere limitata a max_speed.
Il concetto chiave è che boost non sa nulla delle motociclette. Lavora solo con Vehicle. Tuttavia, grazie al upcasting, la tua motocicletta può usare questa funzione generica per modificare i dati del veicolo che incorpora.
Provalo tu
#include <stdio.h>
#include "vehicle.h"
int main() {
int initial_speed, max_speed, has_sidecar, boost_amount;
// Leggi gli 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 il puntatore Motorcycle* in Vehicle* per passarlo alla funzione boost
// TODO: Stampa le informazioni sulla motocicletta
return 0;
}
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
1Basi di programmazione modulare
File di intestazioneGuardie di inclusioneFile sorgenteFunzioni staticheRipasso: calcolatrice modulare4Incapsulamento
Il concetto di puntatori opachiDefinire struct opacheGetter e setterLa convalida nei setterRiepilogo: scatola segreta2Oggetti e metodi
Le struct come oggettiIl puntatore 'Self'Correttezza constPuntatore o valoreMetodi di supportoRiepilogo: gestore di punti5Progetto: Conto bancario semplice
Configurazione del progettoImplementazione del conto8Polimorfismo
Puntatori a funzione nelle structSimulare i metodiIl concetto di interfacciaImplementare le interfacceIterazione polimorficaRiepilogo: Greeter11Pattern di progettazione in C
Pattern SingletonPattern FactoryPattern IteratorRiepilogo: Factory di Logger3Ciclo di vita degli oggetti
Pattern del costruttorePattern del distruttoreInizializzazione sullo stackCopia profondaRiepilogo: wrapper di stringhe6Ereditarietà tramite composizione
Incorporamento delle structLa regola del primo membroAccesso ai membri della classe baseUpcastingRiepilogo: gerarchia di forme9Progetto: Disegnatore di forme
Panoramica del progettoImplementazione del cerchioImplementazione del rettangoloUtilizzo polimorficoContenitore di formeEsercitati da solo: Compilatore C online