Menu
CoddyTech

Upcasting

Parte de la sección Programación Orientada a Objetos del Journey de C de Coddy. Lección 31 de 61.

La conversión ascendente consiste en tratar un tipo específico (derivado) como su tipo más general (base). En el modelo de composición de C, esto significa pasar un puntero a una estructura que incluye un tipo base a una función que espera el tipo base.

Considera una estructura base Vehicle y una Car que la contiene:

typedef struct {
    int speed;
} Vehicle;

typedef struct {
    Vehicle vehicle;  // Base como primer miembro
    int doors;
} Car;

Ahora imagina una función genérica que funciona con cualquier vehículo:

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

Gracias a la regla del primer miembro, podemos pasar un Car* a esta función convirtiéndolo a Vehicle*:

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

Esto es una conversión ascendente: estamos pasando de un tipo específico a uno general. La función accelerate no sabe que está trabajando con un Car; solo ve un Vehicle. Esto te permite escribir código reutilizable que opera sobre el tipo base y acepta cualquier tipo derivado que lo incluya.

challenge icon

Desafío

Fácil

Construyamos un sistema de transporte sencillo que demuestre cómo funciona la conversión ascendente. Crearás un tipo base Vehicle y un tipo más específico Motorcycle, y luego mostrarás cómo una función genérica puede trabajar con ambos mediante la conversión de punteros.

La ventaja de la conversión ascendente es que puedes escribir funciones para el tipo base, y funcionarán sin problemas con cualquier tipo derivado que lo incluya. Tu motocicleta «es un» vehículo, así que cualquier función que espere un Vehicle* debería poder procesarla.

Organizarás tu código en tres archivos:

  • vehicle.h: Define la jerarquía de estructuras con protecciones de inclusión. Crea una estructura Vehicle con dos campos: speed (un entero para la velocidad actual) y max_speed (un entero para la velocidad máxima del vehículo). Luego define una estructura Motorcycle que incluya Vehicle como su primer miembro y añada un campo has_sidecar (un entero, donde 1 significa que sí y 0 que no). Declara dos funciones: boost, que recibe un Vehicle* y una cantidad para aumentar la velocidad, y print_motorcycle, que recibe un Motorcycle*.
  • vehicle.c: Implementa ambas funciones. La función boost debe aumentar la velocidad del vehículo en la cantidad indicada, pero limitarla a max_speed; si la nueva velocidad superara el máximo, asígnale max_speed. La función print_motorcycle debe mostrar toda la información de la motocicleta, incluidos los datos de su vehículo integrado.
  • main.c: Crea una Motorcycle e inicializa todos sus campos. Luego demuestra la conversión ascendente llamando a la función boost: convierte tu Motorcycle* en un Vehicle* para pasarlo a esta función genérica. Después de aumentar la velocidad, imprime la información de la motocicleta para ver el resultado.

Recibirás cuatro datos de entrada: la velocidad inicial de la motocicleta, su velocidad máxima, si tiene un sidecar (1 o 0) y la cantidad del aumento.

La salida debería verse así:

Speed: 75
Max Speed: 120
Sidecar: Yes

Donde 75 es la velocidad después del aumento (inicial 50 + aumento 25), 120 es la velocidad máxima y Yes o No indica si la motocicleta tiene un sidecar. Si el aumento hiciera que la velocidad superara max_speed, esta debería limitarse a max_speed.

La clave del aprendizaje aquí es que boost no sabe nada sobre motocicletas. Solo trabaja con Vehicle. Sin embargo, mediante la conversión ascendente, tu motocicleta puede usar esta función genérica para modificar los datos de su vehículo integrado.

Pruébalo tú mismo

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

int main() {
    int initial_speed, max_speed, has_sidecar, boost_amount;
    
    // Lee las entradas
    scanf("%d", &initial_speed);
    scanf("%d", &max_speed);
    scanf("%d", &has_sidecar);
    scanf("%d", &boost_amount);
    
    // TODO: Crea una Motorcycle e inicializa todos sus campos
    // Recuerda: Motorcycle contiene Vehicle como su primer miembro
    
    // TODO: Demuestra la conversión a un tipo base llamando a boost
    // Convierte tu Motorcycle* a Vehicle* para pasarlo a la función boost
    
    // TODO: Muestra la información de la motocicleta
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de C online