Menu
CoddyTech

Upcasting

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

Upcasting bezeichnet den Vorgang, einen spezifischen (abgeleiteten) Typ als 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;  // Basistyp als erstes Element
    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 dieser Funktion ein Car* übergeben, indem wir es 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. So 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 zeigt. Du erstellst einen Basistyp Vehicle und einen spezifischeren Typ Motorcycle und zeigst dann, wie eine generische Funktion mit beiden über Zeiger-Casting arbeiten kann.

Der Vorteil von Upcasting ist, dass du Funktionen für den Basistyp schreiben kannst, die 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 auf drei Dateien:

  • vehicle.h: Definiere deine Struct-Hierarchie mit Include-Guards. Erstelle ein 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 dann ein Motorcycle-Struct, das Vehicle als erstes Element einbettet und ein Feld has_sidecar 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, und print_motorcycle, die einen Motorcycle* entgegennimmt.
  • vehicle.c: Implementiere beide Funktionen. Deine Funktion boost soll die Geschwindigkeit des Fahrzeugs um den angegebenen Betrag erhöhen, sie jedoch auf max_speed begrenzen. Würde die neue Geschwindigkeit das Maximum überschreiten, setze sie stattdessen auf max_speed. Deine Funktion print_motorcycle soll alle Informationen zum Motorrad anzeigen, einschließlich der eingebetteten Fahrzeugdaten.
  • main.c: Erstelle ein Motorcycle und initialisiere alle seine Felder. Zeige dann Upcasting, indem du die Funktion boost aufrufst: Wandle deinen Motorcycle* in einen Vehicle* um, um ihn an diese generische Funktion zu übergeben. Gib nach der Erhöhung die Informationen zum Motorrad 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 so aussehen:

Speed: 75
Max Speed: 120
Sidecar: Yes

Dabei ist 75 die Geschwindigkeit nach der Erhöhung (Anfangsgeschwindigkeit 50 + Erhöhung 25), 120 die Höchstgeschwindigkeit, und Yes oder No gibt an, 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 hier ist, dass boost nichts über Motorräder weiß. Die Funktion arbeitet nur mit Vehicle. Durch Upcasting kann dein Motorrad dennoch diese generische Funktion nutzen, um seine eingebetteten Fahrzeugdaten zu ändern.

Probier es selbst

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

int main() {
    int initial_speed, max_speed, has_sidecar, boost_amount;
    
    // Eingaben einlesen
    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
    // Denke daran: Motorcycle enthält Vehicle als erstes Mitglied
    
    // TODO: Demonstriere Upcasting durch einen Aufruf von boost
    // Wandle deinen Motorcycle* in Vehicle* um, um ihn an die Funktion boost zu übergeben
    
    // TODO: Gib die Informationen des Motorrads 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