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: 50Questo è 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.
Sfida
FacileCostruiamo 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 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 includeVehiclecome 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à per 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à supererebbe il massimo, impostala invece amax_speed. La funzioneprint_motorcycledeve mostrare tutte le informazioni sulla motocicletta, compresi i dati del veicolo incluso.main.c: Crea unaMotorcyclee inizializza tutti i suoi campi. Poi mostra l'upcasting chiamando la funzioneboost: esegui il cast del tuoMotorcycle*aVehicle*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: YesDove 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;
}
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