Funktionszeiger in Structs
Teil des Abschnitts Object Oriented Programming der C-Journey von Coddy — Lektion 38 von 61.
Bisher haben wir Funktionszeiger als eigenständige Variablen verwendet oder sie als Argumente übergeben. Der nächste Schritt in Richtung Polymorphismus besteht darin, einen Funktionszeiger direkt in ein Struct einzubetten – was dem Struct sein eigenes Verhalten verleiht.
Wenn ein Struct einen Funktionszeiger enthält, kann jede Instanz eine andere Funktion enthalten. Das bedeutet, dass sich zwei Objekte desselben Typs unterschiedlich verhalten können, wenn Sie deren Funktionszeiger aufrufen:
typedef void (*PrintFunc)(const char*);
typedef struct {
const char* name;
PrintFunc print; // Funktionszeiger als Member
} Printer;Die Printer-Struktur hat nun zwei Member: Daten (name) und Verhalten (print). Um sie zu verwenden, weisen Sie dem Pointer während der Initialisierung eine Funktion zu:
void loud_print(const char* msg) {
printf("!!! %s !!!\n", msg);
}
int main() {
Printer p;
p.name = "Alert";
p.print = loud_print;
p.print("Hello"); // Ausgabe: !!! Hello !!!
return 0;
}Beachten Sie, wie wir die Funktion über das Struct aufrufen: p.print("Hello"). Dies sieht dem Aufruf einer Methode auf einem Objekt in anderen Sprachen bemerkenswert ähnlich. Das Struct enthält sowohl seine Daten als auch die Funktion, die darauf operiert.
Dieses Muster ist die Grundlage für Polymorphismus in C — verschiedenen Instanzen können unterschiedliche Funktionen zugewiesen werden, was zu unterschiedlichen Verhaltensweisen desselben struct-Typs führt.
Aufgabe
EinfachLassen Sie uns ein Notifier-System bauen, das demonstriert, wie Structs ihr eigenes Verhalten durch Funktionszeiger mitführen können.
Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:
notifier.h: Definieren Sie einen Funktionszeigertyp namensNotifyFunc, der einenconst char*-Parameter entgegennimmt und nichts zurückgibt. Definieren Sie dann einNotifier-Struct, das einenname(einconst char*) und einennotify-Funktionszeiger vom TypNotifyFuncenthält.main.c: Binden Sie Ihren Header ein und implementieren Sie zwei Benachrichtigungsfunktionen:alert_notify— gibt die Nachricht im Format[ALERT] messageausinfo_notify— gibt die Nachricht im Format[INFO] messageaus
Notifier-Instanz, verknüpfen Sie die entsprechende Funktion basierend auf der Eingabe und rufen Sie die Benachrichtigung über den Funktionszeiger des Structs auf.
Ihr Programm erhält zwei Eingaben: einen Benachrichtigungstyp (1 für Alert, 2 für Info) und eine anzuzeigende Nachricht.
Weisen Sie basierend auf dem Typ die entsprechende Funktion dem notify-Element Ihres Notifiers zu und rufen Sie sie dann über das Struct auf, um die Nachricht anzuzeigen.
Beispielhafte Ausgabe, wenn der Typ 1 und die Nachricht "System starting" ist:
[ALERT] System startingBeispielhafte Ausgabe, wenn der Typ 2 und die Nachricht "All systems normal" ist:
[INFO] All systems normalDenken Sie daran, Include-Guards in Ihrer Header-Datei zu verwenden und die Funktion über das Struct-Element aufzurufen: n.notify(message)
Probier es selbst
#include <stdio.h>
#include "notifier.h"
// TODO: Implementiere die Funktion alert_notify
// Sollte ausgeben: [ALERT] message
// TODO: Implementiere die Funktion info_notify
// Sollte ausgeben: [INFO] message
int main() {
int type;
char message[256];
// Eingabe lesen
scanf("%d", &type);
getchar(); // Zeilenumbruch konsumieren
fgets(message, sizeof(message), stdin);
// Abschließenden Zeilenumbruch aus message entfernen, falls vorhanden
int len = 0;
while (message[len] != '\0') len++;
if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
// TODO: Erstelle eine Notifier-Instanz
// TODO: Basierend auf type (1 für alert, 2 für info),
// weise die entsprechende Funktion dem notify-Member des Notifiers zu
// TODO: Rufe die Benachrichtigung über den Funktionszeiger des structs auf
// Verwende: n.notify(message)
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-ImplementierungRechteck-ImplementierungPolymorphe VerwendungShape-Container