Shape-Container
Teil des Abschnitts Objektorientierte Programmierung der C-Journey von Coddy. Lektion 48 von 61.
Aufgabe
EinfachBringen wir das Shape-Drawer-Projekt zu seinem großen Finale! Du wirst einen Shape-Container erstellen, der eine gemischte Sammlung von Circles und Rectangles enthält, und anschließend durch diese iterieren, um die Gesamtfläche zu berechnen – und dabei die wahre Stärke des Polymorphismus demonstrieren.
Aufbauend auf allem, was du bisher erstellt hast, wird dein vollständiges Projekt Folgendes enthalten:
shape.hundshape.c: dein grundlegendes Shape-Interface und die Funktionprocess_shape.circle.hundcircle.c: deine Circle-Implementierung mit ihrem Konstruktor und der Flächenberechnung.rectangle.hundrectangle.c: deine Rectangle-Implementierung mit ihrem Konstruktor und der Flächenberechnung.main.c: Hier geschieht die Magie. Du wirst ein Array vonShape*-Zeigern erstellen, das jeden Shape-Typ aufnehmen kann. Fülle es mit einer Mischung aus Circles und Rectangles und durchlaufe anschließend das Array, um die Gesamtfläche aller Shapes zusammen zu berechnen und auszugeben.
Dein Programm erhält die folgenden Eingaben:
- Die Anzahl der zu erstellenden Shapes
- Für jeden Shape: ein Typindikator (
cfür Circle,rfür Rectangle), gefolgt von dessen Abmessungen
Rufe für jeden Shape in deinem Container draw und area selbst über den Shape*-Zeiger auf (shapes[i]->draw(shapes[i]), shapes[i]->area(shapes[i])) und addiere die Fläche zu einer laufenden Gesamtsumme. Verwende hier nicht process_shape aus shape.c: Die Funktion gibt für jeden Shape eine zusätzliche Area:-Zeile aus, die in der erwarteten Ausgabe nicht enthalten ist. Gib nach der Verarbeitung aller Shapes die Gesamtfläche mit 2 Dezimalstellen im Format Total Area: X.XX aus.
Beispiel mit den Eingaben 3, dann c 5.0, r 4.0 3.0, c 2.0:
Drawing Circle with radius: 5.00
Drawing Rectangle with width: 4.00 and height: 3.00
Drawing Circle with radius: 2.00
Total Area: 103.11Beispiel mit den Eingaben 2, dann r 6.0 4.0, r 3.0 2.0:
Drawing Rectangle with width: 6.00 and height: 4.00
Drawing Rectangle with width: 3.00 and height: 2.00
Total Area: 30.00Die wichtigste Erkenntnis ist, dass dein Array Shape*-Zeiger speichert. Es spielt keine Rolle, ob jedes Element tatsächlich ein Circle oder ein Rectangle ist. Wenn du iterierst und über jeden Zeiger draw und area aufrufst, wird automatisch die korrekte Implementierung ausgeführt, abhängig davon, wie der jeweilige Shape erstellt wurde. Das ist Polymorphismus in Aktion: eine Schleife, ein Interface, mehrere Verhaltensweisen.
Denke daran, dass du im Array Zeiger auf die eingebetteten Shape-Member deiner konkreten Shapes speichern musst. Verwende 3.14159 für π bei der Flächenberechnung von Circles.
Wichtig: das Lesen des Shape-Typzeichens: Nachdem du die Anzahl der Shapes mit scanf("%d", &n) eingelesen hast, muss jeder nachfolgende Aufruf zum Lesen des Typzeichens den verbleibenden Zeilenumbruch im Eingabepuffer überspringen. Verwende dafür ein führendes Leerzeichen im Formatstring:
scanf(" %c", &type); // note the space before %cOhne das führende Leerzeichen liest scanf das Zeilenumbruchzeichen, das von der vorherigen Eingabe übrig geblieben ist, anstelle des erwarteten c oder r. Dadurch schlägt die Prüfung des Shape-Typs stillschweigend fehl und es wird keine Ausgabe erzeugt.
Probier es selbst
#include <stdio.h>
#include <stdlib.h>
#include "shape.h"
#include "circle.h"
#include "rectangle.h"
int main() {
// TODO: Lies die Anzahl der Formen ein
// TODO: Allokiere Arrays für Kreise, Rechtecke und Shape*-Zeiger
// TODO: Durchlaufe jede Form, lies ihren Typ und ihre Abmessungen,
// erstelle die Form und speichere einen Zeiger auf ihre Basis im shapes-Array
// TODO: Durchlaufe das shapes-Array, rufe shapes[i]->draw(...) und
// shapes[i]->area(...) direkt auf und akkumulieren die Gesamtfläche
// (rufe process_shape nicht auf: es gibt eine zusätzliche Area-Zeile aus)
// TODO: Gib die Gesamtfläche im Format aus: Total Area: X.XX
// TODO: Gib allokierten Speicher frei
return 0;
}
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