Upcasting
Parte da seção Programação Orientada a Objetos do Journey de C da Coddy. Lição 31 de 61.
Upcasting é o ato de tratar um tipo específico (derivado) como seu tipo mais geral (base). No modelo de composição de C, isso significa passar para uma função que espera o tipo base um ponteiro para uma estrutura que incorpora esse tipo.
Considere uma estrutura base Vehicle e uma Car que a contém:
typedef struct {
int speed;
} Vehicle;
typedef struct {
Vehicle vehicle; // Base como primeiro membro
int doors;
} Car;Agora imagine uma função genérica que funciona com qualquer veículo:
void accelerate(Vehicle* v, int amount) {
v->speed += amount;
}Graças à regra do primeiro membro, podemos passar um Car* para esta função convertendo-o para Vehicle*:
Car my_car = {{0}, 4}; // speed=0, doors=4
accelerate((Vehicle*)&my_car, 50);
printf("Speed: %d\n", my_car.vehicle.speed); // Saída: 50Isso é upcasting: estamos subindo de um tipo específico para um tipo geral. A função accelerate não sabe que está trabalhando com um Car; ela só vê um Vehicle. Isso permite escrever código reutilizável que opera sobre o tipo base e aceita qualquer tipo derivado que o incorpore.
Desafio
FácilVamos criar um sistema de transporte simples que demonstra o upcasting em ação. Você vai criar um tipo base Vehicle e um tipo mais específico Motorcycle e, em seguida, mostrar como uma função genérica pode trabalhar com ambos por meio de conversão de ponteiros.
A vantagem do upcasting é que você pode escrever funções para o tipo base, e elas funcionarão perfeitamente com qualquer tipo derivado que o contenha. Sua motocicleta “é um” veículo, então qualquer função que espere um Vehicle* deve ser capaz de processá-la.
Você vai organizar seu código em três arquivos:
vehicle.h: Defina sua hierarquia de structs com proteção contra inclusões múltiplas. Crie uma structVehiclecom dois campos:speed(um inteiro para a velocidade atual) emax_speed(um inteiro para a velocidade máxima do veículo). Em seguida, defina uma structMotorcycleque contenhaVehiclecomo seu primeiro membro e adicione um campohas_sidecar(um inteiro, em que 1 significa sim e 0 significa não). Declare duas funções:boost, que recebe umVehicle*e uma quantidade para aumentar a velocidade, eprint_motorcycle, que recebe umMotorcycle*.vehicle.c: Implemente ambas as funções. Sua funçãoboostdeve aumentar a velocidade do veículo pela quantidade informada, mas limitá-la amax_speed; se a nova velocidade ultrapassar o máximo, defina-a comomax_speed. Sua funçãoprint_motorcycledeve exibir todas as informações da motocicleta, incluindo os dados do veículo contido nela.main.c: Crie umaMotorcyclee inicialize todos os seus campos. Em seguida, demonstre o upcasting chamando a funçãoboost: converta seuMotorcycle*em umVehicle*para passá-lo a essa função genérica. Depois de aumentar a velocidade, imprima as informações da motocicleta para ver o resultado.
Você receberá quatro valores de entrada: a velocidade inicial da motocicleta, sua velocidade máxima, se ela tem um sidecar (1 ou 0) e a quantidade do aumento de velocidade.
A saída deve ser assim:
Speed: 75
Max Speed: 120
Sidecar: YesEm que 75 é a velocidade após o aumento (velocidade inicial 50 + aumento 25), 120 é a velocidade máxima, e Yes ou No indica se a motocicleta tem um sidecar. Se o aumento fizer a velocidade ultrapassar max_speed, ela deve ser limitada a max_speed.
O principal aprendizado aqui é que boost não sabe nada sobre motocicletas. Ela trabalha apenas com Vehicle. Ainda assim, por meio do upcasting, sua motocicleta pode usar essa função genérica para modificar os dados do veículo contido nela.
Experimente você mesmo
#include <stdio.h>
#include "vehicle.h"
int main() {
int initial_speed, max_speed, has_sidecar, boost_amount;
// Leia as entradas
scanf("%d", &initial_speed);
scanf("%d", &max_speed);
scanf("%d", &has_sidecar);
scanf("%d", &boost_amount);
// TODO: Crie uma Motorcycle e inicialize todos os seus campos
// Lembre-se: Motorcycle incorpora Vehicle como seu primeiro membro
// TODO: Demonstre o upcasting chamando boost
// Converta seu Motorcycle* para Vehicle* para passá-lo à função boost
// TODO: Imprima as informações da motocicleta
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos da Programação Modular
Arquivos de cabeçalhoProteções de inclusãoArquivos-fonteFunções estáticasRevisão: calculadora modular4Encapsulamento
Conceito de ponteiros opacosDefinindo structs opacasGetters e settersValidação em settersRevisão: caixa secreta2Objetos e métodos
Structs como objetosO ponteiro 'Self'Correção de constPonteiro vs. valorMétodos auxiliaresRevisão: Gerenciador de pontos5Projeto: Conta Bancária Simples
Configuração do ProjetoImplementação da Conta3Ciclo de vida do objeto
Padrão de construtorPadrão de destrutorInicialização da pilhaCópia profundaRevisão: wrapper de String6Herança por composição
Incorporação de structRegra do primeiro membroAcessando membros do tipo paiUpcastingRevisão: hierarquia de formas9Projeto: Desenhador de Formas
Visão geral do projetoImplementação do círculoImplementação do retânguloUso polimórficoContêiner de formasPratique por conta própria: Compilador de C online