'Objekt ausgabe (cout)' und 'enum Zugriff'
-
Hallo!
Ich bin Java auf C++ - Umsteiger und habe jetzt dementsprechend einige Fragen.
Konkret hab ich hier eine Aufgabe wo der Main teil schon fertig ist und man
soll eine Klasse "Intervall" erstellen: http://www.wst.univie.ac.at/~wanek/prgersatz/20130227/praktisch.pdf1.ENUM Frage:
jetzt gibt es 4 Arten von Intervallen, jeweils mit anderen Klammern:
geschlossen [a,b,]
offen (a,b)
linksoffen (a,b]
rechtsoffen [a,b)mein Klassen code sieht mal so aus:
class Intervall{ private: double oben; double unten; enum Typ {geschlossen,offen,linksoffen,rechtsoffen}; public: Intervall(double oben, double unten); double len() const; }; Intervall::Intervall(double oben,double unten){ if(oben<unten){ throw 0; } this->oben = oben; this->unten = unten; }Jetzt ist im Main teil aber dieses Codestück:
... Intervall i1(1,3);// [1,3] default-Intervall ist geschlossen Intervall i2(1,4,Intervall::linksoffen); // (1,4] Intervall i3(1,4,Intervall::rechtsoffen); // [1,4) ...Brauch ich hier einen zweiten Konstuktor? Und auf was wird bei Intervall::linksoffen zugegriffen??
Mein gedanke war, dass ich überprüfe welches enum ich übermittelt bekomme und dementsprechend die korrekten Klammern setzte. Also z.b:if(Typ == 0){ //0 ist gleich enum "geschlossen" cout << "[" << a << b << "]" << endl; }2.Objekt-Ausgabe Frage
Außerdem weiß ich nicht sicher wie man eine Klasse ausgeben kann.. in der Main ist vorgeschrieben:.. cout << i1 << endl; // Ausgabe: [1,3] ..In Java ist es möglich in eine Klasse eine toString() methode zu schreiben und somit konnte man einfach im Main ausgeben. Aber erstens darf ich hier vermutlich keine Strings verwenden ("keine weiteren includes") und zweitens weiß ich net wie ich einfach durch "cout << 'objekt'" ausgeben kann??
Bitte bitte um Hilfe!!

-
Du musst deine Klasse entsprechend umschreiben, sodass der Konstruktor auch den Typ des Intervalls nehmen und diesen in der Klasse speichern kann:
class Intervall { private: double oben; double unten; public: enum Typ // Der Typ muss public sein. { geschlossen, offen, linksoffen, rechtsoffen }; private: Typ typ; public: Intervall(double oben, double unten, Typ); double len() const; };Intervall::Intervall( double oben, double unten, Typ t ) : // Mit diesem Doppelpunkt beginnst du eine Initialisierungsliste oben(oben), unten(unten), typ(t) { if(oben < unten) throw std::invalid_argument(""); // Statt 0 solltest du schon eine richtige Exception-Klasse werfen, evt. mit Nachricht }Außerdem weiß ich nicht sicher wie man eine Klasse ausgeben kann..
Indem du den operator<< überlädst. Das wäre die fortgeschrittenere Variante. Sonst kannst du auch vorerst eine Methode print_to(std::ostream& os) schreiben.
Aber zu erklären, wie das alles funktioniert, das würde den Rahmen dieses Threads sprengen. Lernst du mit einem Buch? Wenn nein, dann verweise ich dich auf die Linkliste.
if(Typ == 0)Diese Abfrage sollte lieber den Enumerator nehmen:
if(typ == /*Invervall::*/geschlossen)
-
coder88 schrieb:
Jetzt ist im Main teil aber dieses Codestück:
... Intervall i1(1,3);// [1,3] default-Intervall ist geschlossen Intervall i2(1,4,Intervall::linksoffen); // (1,4] Intervall i3(1,4,Intervall::rechtsoffen); // [1,4) ...Brauch ich hier einen zweiten Konstuktor?
Ich würde einen Konstruktor schreiben, der den Intervall-Typ als drittes Argument beinhaltet. Hier kannst du dann Intervall::geschlossen als default-Parameter setzen.
coder88 schrieb:
.. cout << i1 << endl; // Ausgabe: [1,3] ..In Java ist es möglich in eine Klasse eine toString() methode zu schreiben und somit konnte man einfach im Main ausgeben.
operator<< überladen
-
Danke für die rasche Antwort! Hat mir sehr geholfen!!
Ich lerne mithilfe des Buches "Einstieg in C++" von Galileo Computing.Hab jetzt weitergearbeitet bin mir aber nicht sicher beim überschreiben des Ausgabeoperators:
#include<iostream> using namespace std; class Intervall{ public: enum Typ {geschlossen,offen,linksoffen,rechtsoffen}; Intervall(double o, double u, Typ); char getKlammerRechts() const; char getKlammerLinks() const; bool contains(Intervall i) const; private: double oben; double unten; Typ typ; public: inline double len() const {return (oben-unten);} //Gibt Intervall-Länge zurück }; //Konstruktor Intervall::Intervall(double o,double u, Typ t): oben(o), unten(u), typ(t) { if(o<u) { throw invalid_argument(""); } } char Intervall::getKlammerRechts() const { switch(typ) { case geschlossen: case linksoffen: return ']'; case offen: case rechtsoffen: return ')'; } } char Intervall::getKlammerLinks() const { switch(typ) { case geschlossen: case rechtsoffen: return '['; case offen: case linksoffen: return '('; } } //Ueberladen des AusgabeOperators ostream& operator<<(ostream& Stream, const Intervall& i) { return Stream << i.getKlammerLinks() << unten << ", " << oben << i.getKlammerRechts(); }Wie kann ich denn auf die Klassenvariablen unten,oben zugreifen? Die sind ja private und ich hab hier eine Globale Funktion.. seh ich das mal richtig?
Dann hätte ich gedacht ich bau einfach getter und setter dafür ein, aber vermutlich ist es besser mit Zeiger zu arbeiten??
Das Zeiger konzept ist mir nur noch nicht so geläufig, da ich ja Java gewohnt war
Wäre also für Lösungsvorschläge seeeeehr dankbar!!Außerdem hab ich das mit ostream hauptsächlich aus dem Buch. Was bedeutet denn das &-Zeichen NACH dem ostream& und Intervall&?!
Davor bekomme ich die Adresse der Variablen, das ist mir schon klar. Aber danach?!Danke im Vorraus für die Aufklärung

-
Sone schrieb:
Aber zu erklären, wie das alles funktioniert, das würde den Rahmen dieses Threads sprengen.
Also so schwer ist das jetzt auch nicht:
// H-File #include <iosfwd> class Intervall { public: // public-Methoden schreibt man in C++ zuerst enum Typ // Der Typ muss public sein. { geschlossen, offen, linksoffen, rechtsoffen }; Intervall(); Intervall( double oben, double unten, Typ typ = geschlossen ); // ich hätte hier eher rechtsoffen als Default bevorzugt double len() const; friend std::ostream& operator<<( std::ostream& out, const Intervall& i ); private: // .. was hier steht ist privat und für den Anwender weniger interessant double oben; double unten; Typ typ; static char left_brace[4]; static char right_brace[4]; }; // CPP-File #include <ostream> char Intervall::left_brace[] = { '[', '(', '(', '[' }; char Intervall::right_brace[] = { ']', ')', ']', ')' }; Intervall::Intervall( double oben, // 'links', 'rechts' wäre doch sinnvoller double unten, Typ t ) : // Mit diesem Doppelpunkt beginnst du eine Initialisierungsliste oben(oben), unten(unten), typ(t) { if(oben < unten) throw std::invalid_argument("Intervall: oben < unten"); } Intervall::Intervall() : // Defaultkonstruktor -> Intervall mit einem Punkt bei 0 oben(), // wird so mit 0 belegt unten(), typ(geschlossen) {} std::ostream& operator<<( std::ostream& out, const Intervall& i ) { return out << Intervall::left_brace[i.typ] << i.unten << ';' << i.oben << Intervall::right_brace[i.typ]; } // Demo #include <iostream> int main() { using namespace std; cout << Intervall( 2, 1 ) << endl; cout << Intervall( 2.5, -6.1, Intervall::linksoffen ) << endl; cout << Intervall( 7.1, 0, Intervall::rechtsoffen ) << endl; return 0; }Gruß
Werner
-
Also so schwer ist das jetzt auch nicht:
Nein, aber ich würde nicht so gerne einfach einen fertigen
operator<<hinklatschen und fertig. Er hat es selbst zustande gebracht, aber dennoch.Übrigens, ohne zu kompilieren, müsste denn
left_brace/right_bracenichtpublicsein (undconst)?Siehst du, so etwas meine ich:
Was bedeutet denn das &-Zeichen NACH dem ostream& und Intervall&?!
Das sind Referenzen, und die sind sehr grundlegend. Du solltest unbedingt nochmal weiter vorne Anfangen (oder dir ein besseres Buch besorgen)!
-
coder88 schrieb:
Ich lerne mithilfe des Buches "Einstieg in C++" von Galileo Computing.
->
(oder dir ein besseres Buch besorgen)!
-
Das sind Referenzen, und die sind sehr grundlegend. Du solltest unbedingt nochmal weiter vorne Anfangen (oder dir ein besseres Buch besorgen)!
nein das buch ist schon toll, liegt eher an mir, da ich es zu sehr überflogen habe. Dachte die Unterschiede von Java zu C++ sind nicht so groß.
Referenzen kenn ich, mir war nur nicht klar, dass man das & auch danach schreiben kann. THX!std::ostream& operator<<( std::ostream& out, const Intervall& i )
{
return out << Intervall::left_brace[i.typ] << i.unten << ';' << i.oben << Intervall::right_brace[i.typ];
}das mit i.unten bzw. i.oben funktioniert bei mir nicht! Dachte auch, dass das so funktioniert, aber ich schätze wegen private hab ich da keinen Zugriff darauf. Brauch ich also getter??
Danke jedenfalls für den aufwand!! Hat mir wieder sehr geholfen!
-
coder88 schrieb:
Wie kann ich denn auf die Klassenvariablen unten,oben zugreifen? Die sind ja private und ich hab hier eine Globale Funktion.. seh ich das mal richtig?
Ja - siehst Du richtig.
Zugriff erfolgt wie bei public Members - also://Ueberladen des AusgabeOperators ostream& operator<<(ostream& Stream, const Intervall& i) { return Stream << i.getKlammerLinks() << i.unten << ", " << i.oben << i.getKlammerRechts(); }.. und damit das möglich ist, deklariere die Funktion als friend (s. mein Listing Zeile 17)
getKlammerLinks/Rechts() kannst Du dann private machen.coder88 schrieb:
Dann hätte ich gedacht ich bau einfach getter und setter dafür ein, ..
getter/setter sollte man vermeiden. Besonders setter!
coder88 schrieb:
..aber vermutlich ist es besser mit Zeiger zu arbeiten??
In diesem Fall gar nicht. Außerdem löst das das Problem nicht.
Gruß
Werner
-
Sone schrieb:
Übrigens, ohne zu kompilieren, müsste denn
left_brace/right_bracenichtpublicsein (undconst)?constist sinnvoll (hatte ich vergessen);publicist unnötig, da der Zugriff nur aus einerfriend-Funktion heraus erfolgt... compilier's halt
