Universität der Bundeswehr Fakultät für Informatik – Institut 2 Priv.-Doz. Dr. Lothar Schmitz FT 2006 Übungsblatt 2 Lösungsvorschlag Objektorientierte Programmierung 24. 04. 2006 Lösung 5 (Vererbung - Trace (Klausur FT 2001)) a) b) Die Objekte können von Unfug und Schrott erzeugt werden. c) Die nummerierten Zeilen waren gefordert. Die Reihenfolge von schrott.was() und unfug.was() ist natürlich frei wählbar. Objekte erzeugen (nicht in Lösung gefordert): -->>new Unfug(200) Mehr Unfug: Die 47 -->>new Schrott(100) Mehr Unfug: Eine 47 Mehr Schrott: Eine 47 -->>Outputs: -->>schrott.was(): Mehr Unfug: Eine 47 Mehr Schrott: Eine 47 Verschiedener Schrott JaJa Eine 11 Die 11 -->>unfug.was(): JaJa Die 47 (Zeile (Zeile (Zeile (Zeile (Zeile (Zeile (Zeile (Zeile 1) 2) 3) 4) 5) 6) 7) 8) (Zeile 9) (Zeile 10) 1 Lösung 6 (GEO Paket: UML-Klassendiagramm) a) b) Die toString-Methode einer Klasse wandelt die Objekte in Strings um. Da innerhalb eines Objektes wiederum andere Objekte enthalten sind (Aggregation/Composition), ist es eventuell notwendig, auch diese in den String einzugliedern. Beispielsweise sind bei einer Strecke Anfangs- und Endpunkt als Koord-Objekte gespeichert. Somit müssen diese auch in einen String umgewandelt werden, wozu die toString-Methode dieser Objekte genutzt wird. Je nach Schachtelung der Objekte kann der Aufruf der toString-Methode eines Objektes viele rekursiv geschachtelte Aufrufe anderer toString-Methoden nach sich ziehen. c) Vererbung wird in der GEO-Software genutzt, um eine Hierarchie geometrischer Figuren aufzubauen. Der Kopf der Hierarchie in GEO ist die Klasse Figur (die wiederum von java.lang.Object abgeleitet ist). Es wird vorausgesetzt, dass jede Figur an einem Ort (Attribut ort) zu finden ist. Punkt und Linie sind direkte Unterklassen von Figur. Sie erben die nicht-privaten Anteile (hier: alle Methoden). In beiden Klassen werden je nach Notwendigkeit die Methoden clone, toString und equals überschrieben, da beide Klassen spezialisierte geometrische Figuren beschreiben. Weiterhin werden je nach Klasse weitere 2 Methoden hinzugefügt. Die Klassenhierarchie pflanzt sich unter Punkt und Linie fort. Die Klasse Koord wird nicht vererbt, sondern durch Figur und Linie genutzt. Lösung 7 (GEO-Paketergänzung: Inkreis) Die Ausführung von Umkreis.main() ergibt: d1:Dreieck (-2.0,-4.0)(4.0,-2.0)(-2.0,4.0) Berechne Kreis durch die Punkte des Dreiecks d1 s3 von Punkt1 nach Punkt2: Strecke von (-2.0,-4.0) bis (4.0,-2.0) s4 von Punkt1 nach Punkt3: Strecke von (-2.0,-4.0) bis (-2.0,4.0) Mittelsenkrechte von s3: Gerade durch (1.0,-3.0) und (-1.0,3.0) Mittelsenkrechte von s4: Gerade durch (-2.0,0.0) und (-10.0,0.0) Schnittpunkt der Mittelsenkrechten: (0.0,0.0) Radius = Abstand von Punkt1 zu Schnittpunkt: 4.47213595499958 Ergebnis ist der Umkreis des Dreiecks: Kreis um (0.0,0.0) mit Radius 4.47213595499958 Winkel.java: class Winkel { // Daten private Punkt p1, p2, p3; // Methoden zur Kapselung private void setP1(Punkt p1) { this.p1 = p1; } public Punkt getP1() { return this.p1; } private void setP2(Punkt p2) { this.p2 = p2; } public Punkt getP2() { return this.p2; } private void setP3(Punkt p3) { this.p3 = p3; } public Punkt getP3() { return this.p3; } //Konstruktor Winkel(Punkt p1, Punkt p2, Punkt p3) { setP1(p1); setP2(p2); setP3(p3); } // öffentliche Methoden public Gerade winkelhalbierende() { // Idee: Vectoraddition: (p2 -> p1) + (p2 -> p3) ergibt 3 // Parallelogramm und neuen Punkt p4 // Somit ist Winkelhalbierende die Gerade durch p1 und p4 Koord vectorP2_P1 = p1.getOrt().minus(p2.getOrt()); Koord vectorP2_P3 = p3.getOrt().minus(p2.getOrt()); // normieren: vectorP2_P1 = vectorP2_P1.mal(1/vectorP2_P1.betrag()); vectorP2_P3 = vectorP2_P3.mal(1/vectorP2_P3.betrag()); System.out.println(vectorP2_P1); System.out.println(vectorP2_P3); // Parallelogram Koord p4 = vectorP2_P1.plus(vectorP2_P3); Gerade g = new Gerade(new Koord(0, 0), p4); g.verschiebeUm(p2.getOrt()); return g; } public String toString() { String s = "Winkel (p1: " + getP1() +", p2: " + getP2() +", p3: " + getP3() +")"; return s; } public boolean equals(Object o) { if (this.getClass().equals(o.getClass())) { Winkel w = (Winkel) o; return getP1().equals(w.getP1()) && getP2().equals(w.getP2()) && getP3().equals(w.getP3()); } return false; } public Object clone() { return new Winkel(getP1(), getP2(), getP3()); } } Inkreis.java: class Inkreis { public static void main(String args[]) { // Dreieck Dreieck d1 = new Dreieck(new Koord(-2, -4), new Koord(4, -2), new Koord(-2, 4)); System.out.println("d1:" + d1); System.out.println(""); // Kreis durch Dreieckpunkte mittels 2 Strecken und // deren Mittelsenkrecheten System.out.println("Berechne Kreis, der innerhalb des" + " Dreiecks liegt und dessen Seiten berührt" + " (Inkreis).\n"); // Winkel erzeugen und Winkelhalbierende berechnen 4 Winkel w1 = new Winkel(new new new Winkel w2 = new Winkel(new new new Punkt(d1.getQ()), Punkt(d1.getOrt()), Punkt(d1.getP())); Punkt(d1.getOrt()), Punkt(d1.getP()), Punkt(d1.getQ())); System.out.println("Winkel 1:\n" + w1); System.out.println("Winkel 2:\n" + w2); System.out.println(""); // Winkelhalbierende Gerade w1_halb = w1.winkelhalbierende(); Gerade w2_halb = w2.winkelhalbierende(); System.out.println("Winkelhalbierende von w1: " + w1_halb); System.out.println("Winkelhalbierende von w2: " + w2_halb); System.out.println(""); // Schnittpunkt Koord k = w1_halb.schnittMit(w2_halb); System.out.println("Schnittpunkt der Winkelhalbierenden:" + k); System.out.println(""); // Orthogonale zu einer Seite des Dreiecks, verschieben nach k, // Gerade erzeugen und schneiden mit der genutzten Seite. Koord orthogonale = d1.getP().minus(d1.getOrt()).orthogonal(); Gerade senkrecht = new Gerade(k, k.plus(orthogonale)); Koord k2 = new Gerade(d1.getOrt(),d1.getP()).schnittMit(senkrecht); double d = k.minus(k2).betrag(); System.out.println("Radius = Abstand von Punkt1 zu Schnittpunkt:" + d); System.out.println(""); // Kreis System.out.println("Ergebnis ist der Umkreis des Dreiecks:"); Kreis kr2 = new Kreis(k, d); System.out.println(kr2 + "\n"); } } 5