istream rekursiv aufrufen
-
Geht's ein wenig präziser als "funktioniert nicht"?

-
Verstehe ich das richtig? Die Daten deines GeoPoint-Objekts hast du schon mit dem getline()-Aufruf eingelesen und wunderst dich nun, daß sie nicht mehr im istream stehen. Da heißt die Lösung (vermutlich) stringstream.
(btw, was soll die Bedingung
if(!zeile.find("GeoPoint"))...eigentlich bedeuten? find() liefert keinen Boolean zurück, sondern die Position, an der der Teilstring gefunden wurde.)
-
(btw, was soll die Bedingung if(!zeile.find("GeoPoint"))... eigentlich bedeuten? find() liefert keinen Boolean zurück, sondern die Position, an der der Teilstring gefunden wurde.)
Der Compiler sieht aber 0 als wahr und ungleich 0 als false an. Auf jedenfall funktioniert das und im Falle eines Punktes komm ich auch in den angegebenen Teil.
Ich versuch jetzt nochmal mein Problem zu erklären:
Ich habe eine Klasse GeoShape von der die Klassen GeoPoint, GeoPolygon und GeoGroup erben. Ein Geopoint ist nur ein Punkt, ein GeoPolygon ist ein Polygon und eine GeoGoup ist eine Sammlung von Punkten, Polygonen oder wieder Gruppen.
Der Benutzer soll nun über die Kommandozeileneingabe eine Geometrie eingeben können, wofür in jeder Klasse der globale istream überladen wurde
Wenn ich z.B. einen Punkt von der Kommandozeile einlesen will, muss der Benutzer den nach diesem Schema eingeben:
GeoPoint ID: pointtemp Geometrie: (6,6)mit GeoPoint p();
cin >> p;
wird er dann eingelesenWenn ich ein Polygon von der Kommandozeile einlesen will, muss der Benutzer den nach diesem Schema eingeben:
GeoPolygon ID: jPol Geometrie: {(-1,8)(0,10)(-4,11)(3,6)(-1,8)}wieder mit GeoPolygon poly();
cin >> poly;Diese beiden Fälle funktionieren ohne Probleme
Das Problem ist nun die GeoGruppe
**Ich möchte hier in der Überladung des istreams der GeoGroup die istreams der anderen Klassen aufrufen.
**Der Benutzer gibt die GeoGroup dann so ein:
GeoGroup ID: nGG Objekte: < GeoPoint ID: pointtemp Geometrie: (6,6) GeoGroup ID: mGG Objekte: < GeoPoint ID: hPoi Geometrie: (8,10) GeoPolygon ID: jPol Geometrie: {(-1,8)(0,10)(-4,11)(3,6)(-1,8)} > GeoPolygon ID: polygontemp Geometrie: {(4,6)(3,4)(2,5)(4,6)} >Code aus der Überladung des istreams der GeoGroup
// Sollange keine spitze schließende Klammer an Ende einer GeoGroup kommt while(is.peek() != '>') { // Auslesen der Objektbezeichnung getline(is, zeile, '\n'); // Prüfen ob GeoPoint Ojekt eingelesen wurde if(!zeile.find("GeoPoint")) { Hier soll nun der Aufruf des überladenen istream operators des GeoPoints kommen cout << "Punkt" << endl; } // Prüfen ob GeoPolygon if(!zeile.find("GeoPolygon")) Hier soll nun der Aufruf des überladenen istream operators des GeoPolygons kommen cout << "Polygon" << endl; // Prüfen auf GeoGroup if(!zeile.find("GeoGroup")) Hier soll nun der Aufruf des überladenen istream operators der GeoGroup kommen cout << "Gruppe" << endl; }Geht's ein wenig präziser als "funktioniert nicht"?
Leider kann ich es nicht genauer schreiben, da ich nicht weiß wie der Code auszusehen hat und ob ein Aufruf des istream operators>> im Quellcode ohne Kommandozeile überhaupt möglich ist.
-
Gloem schrieb:
(btw, was soll die Bedingung if(!zeile.find("GeoPoint"))... eigentlich bedeuten? find() liefert keinen Boolean zurück, sondern die Position, an der der Teilstring gefunden wurde.)
Der Compiler sieht aber 0 als wahr und ungleich 0 als false an.
Andersum.
Auf jedenfall funktioniert das und im Falle eines Punktes komm ich auch in den angegebenen Teil.
Du suchst nicht, sondern prüfst nur, ob zeile mit dem gesuchten String anfängt. Nur dann liefert dir find nämlich 0 zurück.
Geht's ein wenig präziser als "funktioniert nicht"?
Leider kann ich es nicht genauer schreiben, da ich nicht weiß wie der Code auszusehen hat und ob ein Aufruf des istream operators>> im Quellcode ohne Kommandozeile überhaupt möglich ist.
Klar ist das möglich. Aber du musst den Fehler besser beschreiben. Mit "funktioniert nicht" kann niemand etwas anfangen.
Was ist das beobachtete Verhalten genau? Fehlermeldung, falsche Werte, Absturz usw. Irgendwie glaube ich nicht, dass da nur eine Meldung "Funktioniert nicht" auf dem Bildschirm erscheint.
-
Du hast per getline() die komplette Zeile eingelesen, in der die Beschreibung des GeoPoint steht - das heißt, dein Lesezeiger steht nun am Anfang von Zeile 4 und der GeoPoint::operator>> versucht, diese Zeile als Punkt zu lesen, was vermutlich schiefgeht. Die Lösung sieht etwa so aus:
GeoPoint p; istringstream l(zeile); l>>p; ...(nur bei der mehrzeiligen Darstellung einer GeoGroup könnte es da ein Problem geben - weil du dort die erste Zeile in der Hand und den Rest der Daten im Stream hast. Als Lösungsansatz könntest du deren operator>> so anpassen, daß er auch Eingaben akzeptiert, die mit ">" beginnen (da mußt du die Gruppen-ID nachträglich ergänzen).)
PS: Eine Alternative Lösung wäre es, GeoShape eine read-Methode zu geben:
void read(string first_line,istream& input) { if(first_line=="") getline(input,first_line); ... } istream& operator>>(istream& input,Geoshape&data) { data.read("",input); return input; }
-
cool, danke.
Das erste funktioniert schonmal, jetzt muss ich nur noch an die GeoGroup machen
-
Ok, es funktioniert doch nicht, er wirft mich dann bei der Ausgabe raus wenn ich versuche mittels dynamic_cast mein Objekt aus dem Vektor wieder herauszubekommen
GeoPoint *pGeoPoint = dynamic_cast<GeoPoint*>(*first);Dann eben doch die zweite wahrscheinlich auch bessere Variante:
Aber wofür brauch ich in der read-Methode den String? Geht das nicht auch ohne?
GeoGroup.h
class GeoGroup : public GeoShape { public: ... void read(istream& input); ... };GeoGroup.cpp
void GeoGroup::read(istream& input) { // Hier den ganzen Rotz aus der alten istream-Methode if(!zeile.find("GeoGroup")) read(is); } // Überladen des globalen Output-Streams für die Eingabe einer GeoGroup istream& operator>>(istream& is, GeoGroup& g) { g.read(is); return is; }
-
Gloem schrieb:
Ok, es funktioniert doch nicht, er wirft mich dann bei der Ausgabe raus wenn ich versuche mittels dynamic_cast mein Objekt aus dem Vektor wieder herauszubekommen
GeoPoint *pGeoPoint = dynamic_cast<GeoPoint*>(*first);Mit was für einer Meldung wirft er dich heraus? Und was genau steht in first? Und wie wird es gefüllt?
Dann eben doch die zweite wahrscheinlich auch bessere Variante:
Aber wofür brauch ich in der read-Methode den String? Geht das nicht auch ohne?
Damit wollte ich das Problem aushebeln, daß du möglicherweise den ersten Teil deines Objekts schon ausgelesen hast, wenn du den Stream weitergibst (IOStream's bieten zwar die Möglichkeit, eingelesene Zeichen zurückzuschreiben, aber der Standard garantiert nicht, daß das bei so langen Folgen fehlerfrei funktioniert). Die GeoGroup::read()-Methode kann damit die bereits eingelesene Zeile des Sub-Objekts an dessen read()-Methode weitergeben:
if(zeile.find("GeoPoint")==0) { GeoPoint p; p.read(zeile,input); ... }
-
Klar, an das mit dem String hätte ich auch denken können.
Der Fehler sieht so aus:
PopUp mit Unhandled exception at 0x7c812a5b in Pflichtblatt2.exe: Microsoft C++ exception: std::__non_rtti_object at memory location 0x0013f9ac..Auftreten passiert während des cout << GeoGroup Aufrufs
Das liegte daran, das er die Geometrien nicht korrekt in den Vector speichert.Mein Vector sieht so aus:
typedef vector<GeoShape*> Geovektor;sprich er legt die Objekte Polymorph zur abstrakten Oberklasse GeoShape ab
Eingefügt werden die mit dieser Methode:
// Methode um GeoObjekte zur GeoGroup hinzuzufügen void GeoGroup::addGeoObject(GeoShape* geo) { itsgeos.push_back(geo); }aus der Mainmethoder heraus funktioniert auch super, nur aus der neuen read-Methode nicht, da ich es nicht hinbekomme, einen GeoShape zu erzeugen
if(!zeile.find("GeoPoint")) { GeoPoint temp("0"); istringstream l(zeile); l >> temp; this->addGeoObject(&temp); }
-
Gloem schrieb:
aus der Mainmethoder heraus funktioniert auch super, nur aus der neuen read-Methode nicht, da ich es nicht hinbekomme, einen GeoShape zu erzeugen
Du erzeugst das Objekt schon - es lebt nur nicht allzu lange, nämlich nur bis zur schließenden geschweiften Klammer. Danach hast du einen Zeiger auf ein nicht mehr existierendes Objekt in deinem vector.
Leg die Objekte mit new an.
-
Du erzeugst schon einen GeoShape, aber nur lokal - am Ende des if()-Blocks wird temp wieder vernichtet und der Zeiger, den du dir gemerkt hast, verweist auf irgendwelchen Datenmüll. Als Lösung mußt du dir dein Objekt auf dem Heap anlegen (und z.B. im Destruktor der GeoGroup wieder freigeben*):
if(!zeile.find("GeoPoint")) { GeoPoint* temp= new GeoPoint("0"); istringstream l(zeile); l >> *temp; this->addGeoObject(temp); }* Aber ich bin mir hier nicht ganz sicher über die Besitzverhältnisse (kann der selbe Punkt in mehreren Gruppen enthalten sein?) - besser wäre es womöglich, Smart-Pointer zu verwenden.
-
Klar, danke.
Hatte es auch schon mit new() erzeugt aber vergessen das Referenzzeichen bei
this->addGeoObject(temp);zu entfernen und dann hatte ich an der Baustelle erstmal aufgegeben
-
Gloem schrieb:
Der Fehler sieht so aus:
PopUp mit Unhandled exception at 0x7c812a5b in Pflichtblatt2.exe: Microsoft C++ exception: std::__non_rtti_object at memory location 0x0013f9ac..Ist
GeoShapedynamisch? Wenn nicht füge einfach malvirtual ~GeoShape() { }hinzu.
-
Einmal muss ich glaub ich noch:
meine beiden Methoden istream& operator>>(..) und read(...) sehen nun so aus:
// Methode zum Einlesen einer GeoGroup void GeoGroup::read(string first_line, istream& is) { // Eingabe in der Form: // GeoGroup ID: nGG Objekte: // < // GeoPoint ID: pointtemp Geometrie: (6,6) // GeoGroup ID: mGG Objekte: // < // GeoPoint ID: hPoi Geometrie: (8,10) // GeoPolygon ID: jPol Geometrie: {(-1,8)(0,10)(-4,11)(3,6)(-1,8)} // > // GeoPolygon ID: polygontemp Geometrie: {(4,6)(3,4)(2,5)(4,6)} // > string id; string nix; string zeile; // Wenn keine Zeile übergeben wurde -> erster Aufruf(keine Rekursion) if(first_line=="") { getline(is,first_line, '\n'); } // Abschneiden der ersten Teils des String bis zur ID id = first_line.substr(12, first_line.length()); // Abschneiden des hinteren Teils des Strings zur ID id = id.substr(0, id.find(" ")); // Setzen der eingelesenen ID this->setID(id.c_str()); // Bis zum Ende der Zeile lesen getline(is, nix, '\n'); // Die öffnende spitze Klammer einer Geogroup überlesen getline(is, nix, '\n'); // Solange weiterlesen bis eine schließende spitze Klammer auftaucht while(is.peek() != '>') { // Auslesen der Objektbezeichnung getline(is, zeile, '\n'); // Prüfen ob GeoPoint if(!zeile.find("GeoPoint")) { GeoPoint* temppoi = new GeoPoint("0"); istringstream l(zeile); l >> *temppoi; this->addGeoObject(temppoi); } // Prüfen ob GeoPolygon if(!zeile.find("GeoPolygon")) { GeoPolygon* temppol = new GeoPolygon("0"); istringstream l(zeile); l >> *temppol; this->addGeoObject(temppol); } // Prüfen auf GeoGroup if(!zeile.find("GeoGroup")) { GeoGroup* tempgg = new GeoGroup("0"); // Rekursiver Aufruf der read-Methode mit der Übergabe des GeoGroup-Anfangstrings (*tempgg).read(zeile, is); this->addGeoObject(tempgg); } } }// Überladen des globalen Output-Streams für die Eingabe einer GeoGroup istream& operator>>(istream& is, GeoGroup& g) { // Aufruf der Methode zum Einlesen einer GeoGroup g.read("", is); return is; }Das Problem ist nun, das wohl nicht mehr alles verarbeitet wird und ich weiß nicht warum:
Eingabe:
GeoGroup ID: nGG Objekte: < GeoPoint ID: pointtemp Geometrie: (6,6) GeoGroup ID: mGG Objekte: < GeoPoint ID: hPoi Geometrie: (8,10) GeoPolygon ID: jPol Geometrie: {(-1,8)(0,10)(-4,11)(3,6)(-1,8)} > GeoPolygon ID: polygontemp Geometrie: {(4,6)(3,4)(2,5)(4,6)} >Ausgabe:
Ausgabe: GeoGroup ID: Objekte: < GeoGroup ID: Objekte: < GeoPolygon ID: jPol Geometrie: {(-1,8)(0,10)(-4,11)(3,6)(-1,8)} > >Kann mir jemand sagen, warum nicht mehr alle Objekte erzeugt werden? Irgendwie scheint mein this-Zeiger nicht mehr zu funktionieren
-
Du hast ein getline() zu viel in dem Code. Zu Beginn der Zeile 32 steht der Eingabezeiger am Anfang der >-Zeile, dann überliest Zeile 32 diese Eingabezeile und Zeile 34 das erste Element deiner Gruppe.
-
Vielen Dank, darauf hätt ich auch selber kommen können.
Vielen Dank an alle, jetzt funktionierts. So viele und so schnelle Hilfe hatte ich bislang selten in einem Forum