Die First-Member-Regel
Teil des Abschnitts Objektorientierte Programmierung der C-Journey von Coddy. Lektion 29 von 61.
Wenn du eine Struktur als erstes Mitglied einer anderen Struktur einbettest, geschieht etwas Leistungsstarkes: Die Speicheradresse der äußeren Struktur ist identisch mit der Speicheradresse ihres ersten Mitglieds. Dies wird vom C-Standard garantiert.
Betrachte unser vorheriges Beispiel:
typedef struct {
int id;
} Parent;
typedef struct {
Parent parent; // Erstes Mitglied
int grade;
} Child;Wenn du eine Child-Variable erstellst, befindet sich das Parent-Member ganz am Anfang des Speichers von Child. Das bedeutet, dass ein Zeiger auf Child auf genau dieselbe Adresse zeigt wie ein Zeiger auf sein Parent-Member.
Child c;
Child* child_ptr = &c;
Parent* parent_ptr = (Parent*)child_ptr; // Sicherer Cast!Beide Zeiger enthalten dieselbe Adresse. Dadurch kannst du einen Child* an jede Funktion übergeben, die einen Parent* erwartet:
void print_id(Parent* p) {
printf("ID: %d\n", p->id);
}
// In main:
Child c;
c.parent.id = 42;
print_id((Parent*)&c); // Funktioniert perfektDiese Technik bildet die Grundlage der Vererbung in C. Eine für den Basistyp geschriebene Funktion kann mit jedem abgeleiteten Typ arbeiten, solange die Basis zuerst eingebettet ist. Die Typumwandlung ist sicher, weil die Speicherlayouts perfekt übereinstimmen.
Aufgabe
EinfachErkunden wir die Regel des ersten Mitglieds, indem wir eine einfache Tierhierarchie erstellen. Du erstellst ein Animal-Struct als Basistyp und ein abgeleitetes Dog-Struct und demonstrierst anschließend, wie ein Zeiger auf Dog sicher in einen Zeiger auf Animal umgewandelt werden kann.
Die zentrale Erkenntnis, die du anwenden wirst: Wenn Animal das erste Mitglied von Dog ist, teilen sich beide Structs dieselbe Startspeicheradresse. Das bedeutet, dass du einen Dog* an jede Funktion übergeben kannst, die einen Animal* erwartet, indem du den Zeiger umwandelst.
Du wirst deinen Code auf drei Dateien verteilen:
animal.h: Definiere beide Structs mit Include-Schutz. DeinAnimal-Struct sollte ein einziges Feld haben:legs(eine Ganzzahl, die die Anzahl der Beine angibt). DeinDog-Struct sollteAnimalals sein erstes Mitglied einbetten und einname-Feld hinzufügen (ein Zeichenarray mit 50 Zeichen). Deklariere außerdem eine Funktionprint_animal, die einenAnimal*-Parameter übernimmt.animal.c: Implementiere die Funktionprint_animal. Diese Funktion arbeitet mit dem Basistyp. Sie kennt nurAnimalund gibt aus, wie viele Beine das Tier hat.main.c: Erstelle eineDog-Variable und belege ihre Felder (sowohl die Beine des eingebetteten Tiers als auch den Namen des Hundes). Demonstriere anschließend die Regel des ersten Mitglieds, indem du deinenDog*in einenAnimal*umwandelst und ihn anprint_animalübergibst. Gib außerdem den Namen des Hundes separat aus, um das vollständige Bild zu zeigen.
Du erhältst zwei Eingaben: den Namen des Hundes (eine Zeichenkette) und die Anzahl der Beine (eine Ganzzahl).
Deine Ausgabe sollte so aussehen:
Dog: Buddy
Legs: 4Dabei ist Buddy der Name des Hundes und 4 die Anzahl der Beine. Gib zuerst den Namen des Hundes aus main.c aus und rufe dann print_animal mit dem umgewandelten Zeiger auf, um die Anzahl der Beine anzuzeigen.
Dies zeigt, wie eine für den Basistyp (Animal) geschriebene Funktion durch Zeigerumwandlung nahtlos mit einem abgeleiteten Typ (Dog) arbeiten kann: die Grundlage der Vererbung in C.
Probier es selbst
#include <stdio.h>
#include <string.h>
#include "animal.h"
int main() {
// Eingabe lesen
char name[50];
int legs;
scanf("%s", name);
scanf("%d", &legs);
// TODO: Erstelle eine Dog-Variable
// TODO: Setze den Namen des Hundes mit strcpy
// TODO: Setze die Anzahl der Beine (Zugriff über das eingebettete Animal)
// TODO: Gib den Namen des Hundes im Format aus: "Dog: <name>"
// TODO: Cast Dog* zu Animal* und rufe print_animal auf
// Dies demonstriert die First-Member-Regel!
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der modularen Programmierung
Header-DateienInclude GuardsQuelldateienStatische FunktionenWiederholung: Modularer Taschenrechner4Kapselung
Konzept der Opaque PointersOpaque Structs definierenGetter und SetterValidierung in SetternRückblick: Die geheime Box2Objekte und Methoden
Structs als ObjekteDer 'Self'-PointerConst-CorrectnessPointer vs. WertHilfsmethodenZusammenfassung: Point Manager5Projekt: Einfaches Bankkonto
Projekt-SetupImplementierung des Kontos3Objekt-Lebenszyklus
Konstruktor-MusterDestruktor-MusterStack-InitialisierungTiefe KopieRückblick: String-Wrapper6Vererbung durch Komposition
Struct-EinbettungDie First-Member-RegelZugriff auf Parent-MemberUpcastingRückblick: Formenhierarchie9Projekt: Formen-Zeichner
ProjektübersichtKreis-ImplementierungRechteck-ImplementierungPolymorphe VerwendungShape-ContainerÜbe selbstständig: Online-C-Compiler