Methoden simulieren
Teil des Abschnitts Object Oriented Programming der C-Journey von Coddy — Lektion 39 von 61.
Sie haben gesehen, wie man einen Funktionszeiger in einem struct platziert. Die wahre Stärke zeigt sich, wenn Sie verschiedene Funktionen verschiedenen Instanzen desselben struct-Typs zuweisen — so simulieren wir Methoden mit unterschiedlichem Verhalten.
Betrachten Sie ein Struct, das eine Aktion mit anpassbarer Logik darstellt:
typedef void (*ActionFunc)(void);
typedef struct {
const char* name;
ActionFunc execute;
} Action;Beim Erstellen von Instanzen verknüpfen Sie verschiedene Funktionen mit jeder einzelnen:
void say_hello(void) {
printf("Hello!\n");
}
void say_goodbye(void) {
printf("Goodbye!\n");
}
int main() {
Action greet = { "Greet", say_hello };
Action farewell = { "Farewell", say_goodbye };
greet.execute(); // Ausgabe: Hello!
farewell.execute(); // Ausgabe: Goodbye!
return 0;
}Sowohl greet als auch farewell sind vom gleichen Typ (Action), dennoch führt der Aufruf von execute bei jedem zu völlig unterschiedlichen Ergebnissen. Das Struct enthält nicht nur Daten – es enthält Verhalten, das je nach Instanz variiert.
Dieses Muster spiegelt wider, wie Objekte in anderen Sprachen funktionieren: Jedes Objekt kann seine eigene Implementierung einer Methode haben, obwohl sie dieselbe Schnittstelle teilen.
Aufgabe
EinfachLassen Sie uns ein Speaker-System bauen, das demonstriert, wie verschiedene Instanzen desselben Struct-Typs völlig unterschiedliche Verhaltensweisen zeigen können, je nachdem, welche Funktion in sie eingebunden ist.
Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:
speaker.h: Definieren Sie einen Funktionszeigertyp namensSpeakFunc, der keine Parameter entgegennimmt und nichts zurückgibt. Definieren Sie dann einSpeaker-Struct, das einenname(einconst char*) und einenspeak-Funktionszeiger vom TypSpeakFuncenthält.main.c: Binden Sie Ihren Header ein und implementieren Sie drei verschiedene Sprechfunktionen:bark— gibtWoof!ausmeow— gibtMeow!auschirp— gibtChirp!aus
Speaker-Instanzen, die jeweils basierend auf der Eingabe mit einer anderen Funktion verknüpft sind, und rufen Sie derenspeak-Methoden auf, um polymorphes Verhalten in Aktion zu sehen.
Ihr Programm erhält zwei Eingaben: den ersten Lautsprechertyp (1 für bark, 2 für meow, 3 für chirp) und den zweiten Lautsprechertyp (ebenfalls 1, 2 oder 3).
Erstellen Sie zwei Speaker-Instanzen — Sie können sie beliebig benennen (wie z. B. "Dog", "Cat", "Bird" oder einfach "Speaker1", "Speaker2"). Verknüpfen Sie jede Instanz basierend auf ihrem Eingabecode mit der entsprechenden Funktion und rufen Sie dann nacheinander speak für jede Instanz auf.
Beispielhafte Ausgabe, wenn der erste Typ 1 und der zweite Typ 2 ist:
Woof!
Meow!Beispielhafte Ausgabe, wenn der erste Typ 3 und der zweite Typ 3 ist:
Chirp!
Chirp!Die entscheidende Erkenntnis hierbei ist, dass beide Lautsprecher vom selben Typ Speaker sind, aber unterschiedliche Ausgaben erzeugen, da jedem eine andere Funktion seinem speak-Member zugewiesen wurde. Denken Sie daran, Include-Guards in Ihrer Header-Datei zu verwenden.
Spickzettel
Verschiedene Instanzen desselben Struct-Typs können unterschiedliche Funktionszeiger enthalten, was polymorphes Verhalten ermöglicht.
Definieren Sie einen Funktionszeigertyp und ein Struct, das diesen verwendet:
typedef void (*ActionFunc)(void);
typedef struct {
const char* name;
ActionFunc execute;
} Action;Erstellen Sie Instanzen mit zugewiesenen unterschiedlichen Funktionen:
void say_hello(void) {
printf("Hello!\n");
}
void say_goodbye(void) {
printf("Goodbye!\n");
}
int main() {
Action greet = { "Greet", say_hello };
Action farewell = { "Farewell", say_goodbye };
greet.execute(); // Output: Hello!
farewell.execute(); // Output: Goodbye!
return 0;
}Beide Instanzen teilen denselben Typ, zeigen jedoch unterschiedliches Verhalten, wenn ihre Funktionszeiger aufgerufen werden.
Probier es selbst
#include <stdio.h>
#include "speaker.h"
// TODO: Implementiere die bark-Funktion, die "Woof!" ausgibt
// TODO: Implementiere die meow-Funktion, die "Meow!" ausgibt
// TODO: Implementiere die chirp-Funktion, die "Chirp!" ausgibt
int main() {
int type1, type2;
scanf("%d", &type1);
scanf("%d", &type2);
// TODO: Erstelle zwei Speaker-Instanzen
// TODO: Verknüpfe die speak-Funktion des ersten Speakers basierend auf type1
// (1 = bark, 2 = meow, 3 = chirp)
// TODO: Verknüpfe die speak-Funktion des zweiten Speakers basierend auf type2
// (1 = bark, 2 = meow, 3 = chirp)
// TODO: Rufe speak für jeden Speaker der Reihe nach auf
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
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 Kontos8Polymorphismus
Funktionszeiger in StructsMethoden simulierenDas Interface-KonzeptInterfaces implementierenPolymorphe IterationWiederholung: Greeter3Objekt-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-Implementierung