Das Interface-Konzept
Teil des Abschnitts Objektorientierte Programmierung der C-Journey von Coddy. Lektion 40 von 61.
Bisher haben unsere Strukturen Daten und Verhalten miteinander vermischt: zum Beispiel einen Namen zusammen mit einem Funktionszeiger. Aber was wäre, wenn eine Struktur ausschließlich Funktionszeiger enthielte? Dadurch entsteht etwas Mächtiges: ein Interface.
Eine Schnittstelle definiert, welche Operationen verfügbar sind, ohne festzulegen, wie sie funktionieren. Sie ist ein Vertrag, der besagt: „Jedes Objekt, das diese Schnittstelle implementiert, muss diese Funktionen bereitstellen.“
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;Die Struktur ILogger enthält nichts außer einem Funktionszeiger. Sie besitzt keine eigenen Daten. Sie beschreibt ausschließlich Verhalten. Das Präfix „I“ ist eine gängige Konvention und weist darauf hin, dass es sich um eine Schnittstelle handelt.
Jeglicher Code, der ein ILogger akzeptiert, kümmert sich nicht darum, wohin die Protokollnachricht gesendet wird. Sie könnte auf der Konsole ausgegeben, in eine Datei geschrieben oder über ein Netzwerk gesendet werden. Die aufrufende Stelle weiß nur, dass sie log aufrufen kann:
void process(ILogger* logger, const char* msg) {
logger->log(msg); // Wir wissen nicht WIE es loggt
}Diese Trennung ist das Wesen des Polymorphismus. Die Funktion process funktioniert mit jeder Logger-Implementierung. Du kannst Verhaltensweisen austauschen, ohne den Code der Funktion zu ändern. In der nächsten Lektion wirst du konkrete Implementierungen erstellen, die diesen Schnittstellenvertrag erfüllen.
Aufgabe
EinfachErstellen wir eine ICalculator-Schnittstelle: eine Struktur, die ausschließlich Funktionszeiger enthält und festlegt, welche Operationen jeder Taschenrechner unterstützen muss, ohne vorzugeben, wie sie funktionieren.
Du wirst zwei Dateien erstellen, um deinen Code zu organisieren:
calculator.h: Definiere deine Schnittstelle hier. Erstelle einen Funktionszeigertyp namensBinaryOp, der zweiint-Parameter entgegennimmt und einintzurückgibt. Definiere anschließend eineICalculator-Struktur, die ausschließlich zwei Funktionszeiger enthält:operate(vom TypBinaryOp) unddescribe(ein Funktionszeiger, der keine Parameter entgegennimmt und nichts zurückgibt). Diese Struktur ist ausschließlich eine Schnittstelle. Sie enthält keine Daten, sondern nur Verhalten.main.c: Binde deinen Header ein und implementiere konkrete Funktionen, die die Schnittstelle erfüllen können:add: gibt die Summe zweier Ganzzahlen zurückmultiply: gibt das Produkt zweier Ganzzahlen zurückdescribe_add: gibtAdditionausdescribe_multiply: gibtMultiplicationaus
ICalculator-Instanz, verknüpfe sie abhängig von der Eingabe und verwende sie, um eine Berechnung durchzuführen.
Dein Programm erhält drei Eingaben: zwei Ganzzahlen und einen Operationscode (1 für Addition, 2 für Multiplikation).
Verknüpfe deine ICalculator abhängig vom Operationscode mit dem passenden Funktionspaar. Rufe anschließend describe über die Schnittstelle auf, um den Namen der Operation auszugeben, und rufe danach operate auf, um das Ergebnis zu berechnen und auszugeben.
Beispielausgabe für die Eingaben 5, 3 und 1:
Addition
8Beispielausgabe für die Eingaben 4, 7 und 2:
Multiplication
28Die wichtigste Erkenntnis ist, dass deine ICalculator-Struktur einen Vertrag definiert: Jeder Code, der sie verwendet, weiß, dass er describe und operate aufrufen kann, ohne zu wissen, welche konkreten Funktionen verknüpft sind. Denke daran, Include-Guards in deiner Header-Datei zu verwenden.
Probier es selbst
#include <stdio.h>
#include "calculator.h"
// TODO: Implementiere die add-Funktion
// Gibt die Summe von zwei Ganzzahlen zurück
// TODO: Implementiere die multiply-Funktion
// Gibt das Produkt von zwei Ganzzahlen zurück
// TODO: Implementiere die describe_add-Funktion
// Gibt "Addition" aus
// TODO: Implementiere die describe_multiply-Funktion
// Prints "Multiplication"
int main() {
int num1, num2, op_code;
scanf("%d", &num1);
scanf("%d", &num2);
scanf("%d", &op_code);
// TODO: Erstelle eine ICalculator-Instanz
// TODO: Basierend auf op_code (1 für add, 2 für multiply),
// verdrahte den Calculator mit den entsprechenden Funktionen
// TODO: Rufe describe über die Schnittstelle auf
// TODO: Rufe operate über die Schnittstelle auf und gib das Ergebnis aus
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 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Übe selbstständig: Online-C-Compiler