Menu
Coddy logo textTech

Upcasting

Teil des Abschnitts Objektorientierte Programmierung der C-Journey von Coddy. Lektion 31 von 61.

Upcasting bezeichnet den Vorgang, einen spezifischen (abgeleiteten) Typ wie seinen allgemeineren (Basis-)Typ zu behandeln. Im Kompositionsmodell von C bedeutet dies, einen Zeiger auf eine Struktur, die einen Basistyp einbettet, an eine Funktion zu übergeben, die den Basistyp erwartet.

Betrachte eine Vehicle-Basisstruktur und ein Car, das sie enthält:

typedef struct {
    int speed;
} Vehicle;

typedef struct {
    Vehicle vehicle;  // Basis als erstes Mitglied
    int doors;
} Car;

Stell dir nun eine generische Funktion vor, die mit jedem Fahrzeug funktioniert:

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

Dank der first member-Regel können wir einen Car* an diese Funktion übergeben, indem wir ihn in Vehicle* umwandeln:

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

Das ist Upcasting: Wir bewegen uns von einem spezifischen Typ „nach oben“ zu einem allgemeineren. Die Funktion accelerate weiß nicht, dass sie mit einem Car arbeitet; sie sieht nur ein Vehicle. Dadurch kannst du wiederverwendbaren Code schreiben, der mit dem Basistyp arbeitet und dabei jeden abgeleiteten Typ akzeptiert, der ihn einbettet.

challenge icon

Aufgabe

Einfach

Erstellen wir ein einfaches Transportsystem, das Upcasting in Aktion demonstriert. Du erstellst einen Basistyp Vehicle und einen spezifischeren Typ Motorcycle und zeigst anschließend, wie eine generische Funktion durch Pointer-Casting mit beiden arbeiten kann.

Die Stärke des Upcastings besteht darin, dass du Funktionen für den Basistyp schreiben kannst und sie nahtlos mit jedem abgeleiteten Typ funktionieren, der ihn einbettet. Dein Motorrad „ist ein“ Fahrzeug, daher sollte jede Funktion, die einen Vehicle* erwartet, es verarbeiten können.

Du organisierst deinen Code über drei Dateien:

  • vehicle.h: Definiere deine Struct-Hierarchie mit Include-Guards. Erstelle eine Vehicle-Struct mit zwei Feldern: speed (eine Ganzzahl für die aktuelle Geschwindigkeit) und max_speed (eine Ganzzahl für die Höchstgeschwindigkeit des Fahrzeugs). Definiere anschließend eine Motorcycle-Struct, die Vehicle als ihr erstes Mitglied einbettet und ein has_sidecar-Feld hinzufügt (eine Ganzzahl, wobei 1 ja und 0 nein bedeutet). Deklariere zwei Funktionen: boost, die einen Vehicle* und einen Betrag zur Erhöhung der Geschwindigkeit entgegennimmt, sowie print_motorcycle, die einen Motorcycle* entgegennimmt.
  • vehicle.c: Implementiere beide Funktionen. Deine boost-Funktion sollte die Geschwindigkeit des Fahrzeugs um den angegebenen Betrag erhöhen, sie aber bei max_speed begrenzen. Wenn die neue Geschwindigkeit das Maximum überschreiten würde, setze sie stattdessen auf max_speed. Deine print_motorcycle-Funktion sollte alle informationen des Motorrads einschließlich der Daten des eingebetteten Fahrzeugs anzeigen.
  • main.c: Erstelle ein Motorcycle und initialisiere all seine Felder. Demonstriere anschließend Upcasting, indem du die boost-Funktion aufrufst: Wandle deinen Motorcycle* in einen Vehicle* um, um ihn an diese generische Funktion zu übergeben. Gib nach dem Erhöhen der Geschwindigkeit die informationen des Motorrads aus, um das Ergebnis zu sehen.

Du erhältst vier Eingaben: die Anfangsgeschwindigkeit des Motorrads, seine Höchstgeschwindigkeit, ob es einen Beiwagen hat (1 oder 0), und den Erhöhungsbetrag.

Deine Ausgabe sollte wie folgt aussehen:

Speed: 75
Max Speed: 120
Sidecar: Yes

Wobei 75 die Geschwindigkeit nach der Erhöhung ist (anfänglich 50 + Erhöhung 25), 120 die Höchstgeschwindigkeit ist und Yes oder No angibt, ob das Motorrad einen Beiwagen hat. Wenn die Erhöhung die Geschwindigkeit über max_speed hinaus steigern würde, sollte die Geschwindigkeit auf max_speed begrenzt werden.

Die wichtigste Erkenntnis ist, dass boost nichts über Motorräder weiß. Es arbeitet nur mit Vehicle. Durch Upcasting kann dein Motorrad diese generische Funktion dennoch verwenden, um seine eingebetteten Fahrzeugdaten zu verändern.

Probier es selbst

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

int main() {
    int initial_speed, max_speed, has_sidecar, boost_amount;
    
    // Eingaben lesen
    scanf("%d", &initial_speed);
    scanf("%d", &max_speed);
    scanf("%d", &has_sidecar);
    scanf("%d", &boost_amount);
    
    // TODO: Erstelle ein Motorcycle und initialisiere alle seine Felder
    // Denk daran: Motorcycle bettet Vehicle als sein erstes Mitglied ein
    
    // TODO: Demonstriere Upcasting durch den Aufruf von boost
    // Caste dein Motorcycle* zu Vehicle*, um es an die boost-Funktion zu übergeben
    
    // TODO: Gib die Informationen des Motorcycle aus
    
    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C-Compiler