Seite 1 von 6 Prüfung in PROGRAMMIEREN 3 WS 2006/07 Arbeitszeit: 90 min 1.02.2007 Hilfsmittel: beliebige eigene Das Aufgabenblatt bitte abgeben! Name: Viel Erfolg! Allgemeines Es ist ein Programm in C++ zu entwickeln, das zur Berechnung der Leistungsaufnahme von Schaltungskomponenten (Widerständen, Reihen- oder Parallel(teil)schaltungen) in einer Gleichspannungsschaltung dient. Eine Schaltung wird dazu in Teilschaltungen zerlegt. Es gibt drei Schaltungselemente: Resistor SeriesCircuit ParallelCircuit Widerstand Reihen(teil)schaltung Parallel(teil)schaltung Jedes Schaltungselement wird durch eine Klasse dargestellt. Sie sind alle von der abstrakten Klasse Part (wie auf dem Beiblatt (1) dargestellt) abgeleitet. Generelle Informationen und Vorgaben: Ein Objekt der Klasse SeriesCircuit und ParallelCircuit besitzt eine Liste von Zeigern auf Part-Objekte, somit ist es z. B. möglich eine Reihen-/Parallelschaltung aus mehreren Widerständen, Reihenteilschaltungen und Parallelteilschaltungen zusammenzustellen. Diese Liste ist vom Typ Partlist (s. Part.h Zeile 14). Zum Hinzufügen einer Schaltungskomponente (Teilschaltung/Widerstand) in diese Liste wird die Methode addpart()verwendet (s. SeriesCircuit.h Beiblatt (2)). Entfernen geschieht mit removepart(). Die Methode getresistor() liefert im Fall der Klasse Resistor, den durch den Konstruktor festgelegten Widerstandswert. Im anderen Fall (SeriesCircuit und ParallelCircuit) wird der Gesamtwiderstand anhand der Widerstandswerte der in der Zeigerliste befindlichen - Komponenten "on-the-fly" ermittelt. Die Methode setvoltage() legt den Spannungsabfall an der Schaltungskomponente fest. Im Fall von SeriesCircuit und ParallelCircuit werden auch die darin befindlichen Komponenten mit den korrekt ermittelten Spannungen "versorgt". Hinweis: Das Setzen der Spannung des "Gesamtschaltungsobjekt" startet somit die Ermittlung des Spannungsabfalls für alle darin befindlichen Schaltungskomponenten. Die Klasse ParallelCircuit besitzt die gleichen Datenkomponenten und Methoden wie SeriesCircuit (s. Beiblatt (2)). (Im Unterschied zu SeriesCircuit werden nur andere Berechnungsalgorithmen verwendet.) Die Klasse ParallelCircuit kann als vollständig in ParallelCircuit.h und ParallelCircuit.cpp implementiert angesehen werden. Werfen Sie falls verlangt ausschließlich Exceptions vom Typ logic_error. Fangen Sie falls verlangt die Referenz auf ein konstantes exception-objekt. Erklärung der Datenkomponenten der Klasse Part: m_dvoltage Durch setvoltage() festgelegter Spannungsabfall an der Komponente. m_sname Beliebiger symbolische Name der Schaltungskomponente, der durch die entsprechenden Konstruktoren festgelegt wird. m_pparent Zeiger auf die übergeordnete Schaltungskomponente. Diese ist die (Teil)Schaltung, in der die durch das aktuelle Objekt beschriebene Schaltungskomponente enthalten ist. Dadurch wird sichergestellt, dass diese Komponente nur einmal von einer anderen Komponente verwendet wird. Hinweis: Er kann als Zeiger einer einfach verketteten Liste betrachtet werden. Ist der Wert dieser Komponente 0 (bzw. NULL), so beinhaltet das aktuelle Objekt die komplette Schaltung.
Seite 2 von 6 1. Aufgabe (14) 1.1 Erzeugung einer Hilfsklasse (10) Erstellen Sie eine Klasse CalcPower (Datei: CalcPower.h), die als Funktionsobjekt verwendet werden kann. Für diese Klasse wird nur der Funktionsaufrufoperator (als inline-methode) implementiert. Diesem wird nur ein Parameter vom Typ const Part & übergeben. Er errechnet die Leistungsaufnahme der übergebenen Schaltungskomponente mithilfe der folgenden Formel P=U*U/R. Der Funktionswert ist vom Typ double. Hat der Widerstand den Wert 0.0 und ist der Wert der Spannung!= 0.0, so ist eine Exception mit einer Meldung zu werfen, die auch den Namen der Schaltungskomponente beinhaltet. (Beispiel: "Kurzschluss in Komponente R1!" wobei R1 hier der symbolische Name ist). Besitzt die Spannung den Wert 0.0, so wird als Ergebnis 0.0 zurückgeliefert (ohne Berücksichtigung des Widerstandwertes). In der Funktion ist nur eine return-anweisung erlaubt! 1.2 Verständnisfragen (4) Kann die in Aufgabe 1.1 geworfene Exception durch einen catch(...)-handler gefangen werden? Angenommen die Exception wird geworfen aber nirgends gefangen. Wie heißt die Funktion, die in diesem Fall aufgerufen wird? 2. Aufgabe (20) 2.1 Klassendefinition von Resistor (8) Implementieren Sie anhand der nachfolgenden Implementationsvorgaben - die fehlenden inline-methoden der Klasse Resistor auf dem Aufgabenblatt: 1. // Resistor.h: Schnittstelle für die Klasse Resistor. 2. ////////////////////////////////////////////////////////////////////// 3. #ifndef _RESISTOR_H 4. #define _RESISTOR_H 5. 6. #include "Part.h" 7. #include <stdexcept> 8. using namespace std; 9. 10. class Resistor : public Part 11. { 12. double m_dresistor; 13. public: 14. Resistor(const string &name, double res) 15. { 16. 17. 18. 19. } 20. 21. double getresistor() const 22. { 23. 24. 25. } 26. 27. void setvoltage(double volt) 28. { 29. 30. 31. 32. } 33. void output(ostream &out) const; 34. }; 35. #endif 36.
Seite 3 von 6 Konstruktor: Setzen der Datenkomponenten und überprüfen, ob der übergebene Widerstandswert negativ ist, falls dies zutrifft wird die entsprechende Datenkomponente auf 0.0 gesetzt. setvoltage(double volt): Festlegen des Spannungsabfalls an dem durch das Objekt dargestellten Widerstand. Hat der Widerstand den Wert 0.0 und ist der Wert von volt!= 0.0, so ist eine Exception mit einer Fehlermeldung zu werfen, die auch den symbolischen Namen beinhaltet. (Beispiel: "Kurzschluss in Komponente R1!" wobei R1 hier der symbolische Name ist). Andernfalls ist der übergebene Wert in die entsprechende Datenkomponente zu übertragen. getresistor(): Rückgabe des Widerstandwertes. Rückgabe des Wertes der entsprechenden Datenkomponente. 2.2 Implementation der Methode output() der Klasse Resistor (12) Die Datei Resistor.cpp implementiert nur diese Methode. Formulieren Sie den Inhalt dieser Datei auf dem Bearbeitungsblatt. Die Methode gibt Informationen eines "Widerstand"-Objekts wie im nachfolgenden Beispiel dargestellt auf ein ostream-objekt aus. Reihenschaltung: G1 Parallelschaltung: P2 Widerstand: R5 = 2700 Ohm Widerstand: R4 = 330 Ohm Parallelschaltung: P1 Reihenschaltung: S1 Widerstand: R2 = 2700 Ohm Widerstand: R1 = 1000 Ohm Widerstand: R3 = 330 Ohm Widerstand: R6 = 1000 Ohm Die Methode regelt die Ausgabe einer - hier fett dargestellten - Zeile (inkl. nachfolgendem Zeilenumbruch). Es wird der symbolische Name und der Widerstandswert des Objekts ausgegeben. Die evtl. nötigen #include-anweisungen sollen ebenfalls angegeben werden. Die Anzahl der voran gehenden Leerzeichen kann über getparent() Funktionsaufrufe festgestellt werden. 3. Aufgabe (21) 3.1 Klassendiagramm (13) Zeichnen Sie ein Klassendiagramm, das die Beziehungen der Klassen Part, Resistor, SeriesCircuit und ParallelCircuit zueinander darstellt. Die Anzahl, der an der Beziehung beteiligten Objekte (multiplicity) und ggf. vorhandene Navigationsrichtungen sollen erkennbar sein. Auf die Angabe der Klassenmethoden und der Datenkomponenten/Attribute kann verzichtet werden. 3.2 Verständnisfragen (8) Um welches Entwurfsmuster handelt es sich hierbei? Es wird der STL-Container set verwendet. Dieser legt Werte sortiert ab. Nach welchem Kriterium wird sortiert? 4. Aufgabe (34) Implementation der Methoden für SeriesCircuit in SeriesCircuit.cpp Folgenden Methoden können als gegeben vorausgesetzt werden: Konstruktor: Setzen der Datenkomponente, die den symbolischen Namen der Reihen(teil)schaltung festlegt. output(ostream &out): Ausgabe des Textes "Reihenschaltung: ", des symbolischen Namens und eines Zeilenumbruches. Danach werden die output()-methoden, aller durch m_list referierten Objekte nacheinander aufgerufen. removepart(part *comp): Entfernen der durch comp referierten Schaltungskomponente aus der durch das Objekt dargestellten Reihen(teil)schaltung. Die durch comp referierte Teilschaltung/Widerstand wird aus der Liste entfernt und der Zeiger m_pparent
Seite 4 von 6 von comp geeignet zurückgesetzt. Folgende Methoden der Klasse SeriesCircuit sollen von Ihnen implementiert werden: 4.1 Implementation: addpart(part *comp) (10) Hinzufügen der durch comp referierten Schaltungskomponente zu der durch das Objekt dargestellten Reihen(teil)schaltung. Sollte 0 (bzw. NULL) als Zeiger übergeben werden, dann soll die Methode nichts machen. Sollte comp bereits eine Vaterkomponente besitzen, dann soll eine Exception geworfen werden, in deren Fehlermeldung auch der Name der Reihen(teil)schaltung und der Name der durch comp referierten Teilschaltung/Widerstand vorkommt. (Beispiel: "S1: Komponente R4 wird bereits verwendet!" R4 ist hier der Name, des durch comp referierten Widerstands.) Andernfalls wird comp der Liste hinzugefügt und der Zeiger m_pparent von comp geeignet gesetzt. 4.2 Implementation: getresistor() (10) Rückgabe des Gesamtwiderstands der Reihen(teil)schaltung. Dazu werden die Widerstandswerte der in m_list befindlichen Schaltungskomponenten aufaddiert und der Wert an den Aufrufer zurückgegeben. 4.3 Implementation: setvoltage(double volt) (14) Festlegen des Spannungsabfalls an der durch das Objekt dargestellten Reihen(teil)schaltung. Besitzt der Gesamtwiderstand der Teilschaltung den Wert 0.0 und ist der Wert von volt!= 0.0, so ist eine Exception mit einer Fehlermeldung zu werfen, die auch den Namen der Reihen(teil)schaltung beinhaltet. (Beispiel: "Kurzschluss in Komponente S1!" wobei S1 hier der Name der Reihen(teil)schaltung ist.) Sollte volt den Wert 0.0 haben, so darf keine Exception geworfen werden. Die eigentliche Aufgabe besteht dann darin den Wert von volt in die entsprechende Datenkomponente zu übertragen und alle in m_list befindlichen Schaltungskomponenten mit den entsprechenden Teilspannungswerten zu "versorgen". Teilspannungswert=volt*Teilwiderstandswert/(Gesamtwiderstand dieser (Teil)Schaltung) 5. Aufgabe (30) Erstellen eines Testprogramms (30) Erstellen Sie eine int main() Funktion (Datei: main.cpp), welche unter Verwendung der vollständig implementiert vorliegenden Klassen (Part, Resistor, SeriesCircuit, ParallelCircuit und CalcPower) die auf Beiblatt (2) - dargestellte Schaltung abbildet und die Leistungsaufnahme von R1 ausgibt, wenn die Gesamtschaltung mit 5 V versorgt wird. Wird durch den Programmablauf eine Exception geworfen, so ist diese zu fangen und die Fehlermeldung auf cerr auszugeben. Das Programm ist unmittelbar danach zu beenden. Die nötigen #include-anweisungen sollen ebenfalls angegeben werden. Als symbolische Namen sind G1, S1, P1, P2 und R1 bis R6 zu verwenden. In der Funktion main() soll keine dynamische Allokation vorkommen. Es soll nur der Leistungswert für R1 mithilfe eines temporären Funktionsobjekts der Klasse CalcPower auf cout ausgegeben werden. (Beschreibung von CalcPower: s. Aufgabe 1) Es wird keine Eingabe der - zur Berechnung nötigen - Zahlenwerte über Tastatur (oder Datei) verlangt. Sie haben es geschafft!!
Seite 5 von 6 Beiblatt (1) - Prüfung PROGRAMMIEREN 3 Das Beiblatt bitte abgeben! Name: Part.h 1. // Part.h: Schnittstelle für die Klasse Part. 2. ////////////////////////////////////////////////////////////////////// 3. 4. #ifndef _PART_H 5. #define _PART_H 6. 7. #include <set> 8. #include <string> 9. #include <iostream> 10. 11. using namespace std; 12. 13. class Part; 14. typedef set<part *> Partlist; 15. 16. class Part 17. { 18. Part *m_pparent; 19. 20. protected: 21. string m_sname; 22. double m_dvoltage; 23. 24. public: 25. Part() : m_dvoltage(0.0), m_pparent(0) { }; 26. virtual ~Part() { }; 27. 28. virtual void setparent(part *parent) { m_pparent=parent; }; 29. virtual Part *getparent() const { return m_pparent; }; 30. virtual string getname() const { return m_sname; }; 31. 32. virtual double getvoltage() const { return m_dvoltage; }; 33. 34. virtual double getresistor() const = 0; 35. 36. virtual void setvoltage(double) = 0; 37. 38. virtual void output(ostream &out) const = 0; 39. 40. }; 41. 42. #endif 43.
Seite 6 von 6 Beiblatt (2) - Prüfung PROGRAMMIEREN 3 SeriesCircuit.h 1. // SeriesCircuit.h: Schnittstelle für die Klasse SeriesCircuit. 2. ////////////////////////////////////////////////////////////////////// 3. #ifndef _SERIESCIRCUIT_H 4. #define _SERIESCIRCUIT_H 5. 6. #include "Part.h" 7. #include <stdexcept> 8. using namespace std; 9. 10. class SeriesCircuit : public Part 11. { 12. Partlist m_list; 13. 14. public: 15. SeriesCircuit(const string &name); 16. 17. virtual void addpart(part *comp); 18. virtual void removepart(part *comp); 19. double getresistor() const; 20. void setvoltage(double volt); 21. void output(ostream &out) const; 22. 23. }; 24. #endif 25. Schaltbild (Aufgabe 5)