Klasse mit dem << Operator einlesen?
-
Ja das, doch da bekomme ich folgenden Fehler:
3 IntelliSense: Kein ">>"-Operator stimmt mit diesen Operanden überein.
-
Die Klasse hat leider keine Setter, daher musst du folgendes machen oder die Klasse abändern:
istream& operator>>(istream& is, Person& P) { std::string name; int age; is >> name >> age; P = Person(name, age); return is; }
-
wxSkip schrieb:
Die Klasse hat leider keine Setter, daher musst du folgendes machen oder die Klasse abändern:
istream& operator>>(istream& is, Person& P) { std::string name; int age; is >> name >> age; P = Person(name, age); return is; }Das habe ich hinzugefügt, nur es will keine Eingabe annehmen, obwohl es doch aufgerufen wird.
istream& is(Person& P);
-
@winux: Was bedeutet der unkommentierte Code? Kannst du uns mal bitte deinen Code zeigen?
-
Das ganze ginge auch mit friend:
#include <iostream> class Person { std::string name; int alter; public: Person(const std::string& n, int a) : alter(a), name(n) {} Person() : name("Unbekannt"), alter(0) {} std::string Name() const { return name; } int Alter() const { return alter; } friend std::istream& operator>>(std::istream& in, Person& p); }; std::ostream& operator<<(std::ostream& out, const Person& p) { return out << p.Name() << ", " << p.Alter() << " Jahre alt."; } std::istream& operator>>(std::istream& in, Person& p) { std::cout << "Name: "; std::getline(in, p.name); std::cout << "Alter: "; return in >> p.alter; } int main() { Person p; std::cin >> p; std::cout << p; return 0; }Mit friend erlaubst du dem Operator >>, auf private Member von Person zuzugreifen.
Sollte man aber sparsam mit umgehen, da es ja die ganze Datenkapselung durchlöchert. Aber bei nem Operator >> kann man das ruhig machen, denke ich.
-
wxSkip schrieb:
@winux: Was bedeutet der unkommentierte Code? Kannst du uns mal bitte deinen Code zeigen?
Das die Funktion aufgerufen wird.
istream& is(Person& P);Doch es sollte dann hierher Springen:
istream& operator>>(istream& is, Person& P) { string name; int age; is>>name>>age; P = Person(name, age); if(!is) return is; return is; }Und wenn das Programm läuft sollte es doch nach einer Eingabe fragen. Doch das macht es nicht.
-
Da wird keine Funktion aufgerufen. Da wird eine Funktion deklariert...
-
Jetzt habe ich folgendes Problem die prüf Funktion in Konstrutor will ich arbeiten. Die Übung verlangt das man error() aufruft was ich ja gemacht habe.
class Person { private: string name; int age; public: Person(string n, int a):name(n), age(a) { if(a < 0 || a > 150) error("Alter ist ungueltige!"); } Person() : name("Unbekannt"), age(0) {} const string name2() { return name; } const int age2() { return age; } friend istream& operator>>(istream& is, Person& P); };
-
Und was ist jetzt deine Frage?
-
wxSkip schrieb:
Und was ist jetzt deine Frage?
Die frage wenn ich denn Namen eingebe und danach das alter eingebe, und bei alter eine negative Zahl oder größer als 150 eingebe müsste es doch die error Funktion ausführen weil ich ja im Konstruktor das ja definiert habe. Doch es kommt nicht. Wenn ich 789 oder -6 eingebe wird das auch ausgegeben, obwohl es ja abgefangen werden sollte.
-
Vermutlich rufst du in deinem Stream-Operator den Konstruktor nicht auf oder nur den Kopierkonstruktor...
-
wxSkip schrieb:
Vermutlich rufst du in deinem Stream-Operator den Konstruktor nicht auf oder nur den Kopierkonstruktor...
Problem gelöst, habe die Prüfung auch in dem >> Stream geschrieben. Und jetzt funktioniert die Überprüfung auch. Ist das so gut oder gibt es eine besser Lösung dafür?
istream& operator>>(istream& is, Person& P) { cout << "Person und Alter eingeben" << endl; is>>P.name>>P.age; if(P.age < 0 || P.age > 150) error ("Alter ist ungueltige!\n"); if(!is) return is; return is; } ostream& operator<<(ostream& os, Person& P) { return os << P.name2() << " " << P.age2() << endl; } int main() try{ Person P1("Goofy",63); ostream& os(cout<<P1); Person P; istream& is(cin>>P); operator<<(os,P); keep_window_open(); } catch (runtime_error e) { cout << e.what() << '\n'; keep_window_open("~"); }class Person { private: string name; int age; public: Person(string n, int a):name(n), age(a) { if(age < 0 || age > 150) error ("Alter ist ungueltige!"); } Person() : name("Unbekannt"), age(0) {} const string name2() { return name; } const int age2() { return age; } friend istream& operator>>(istream& is, Person& P); };
-
Ich denke, das ist OK so.
-
wxSkip schrieb:
Ich denke, das ist OK so.
OK
-
Da ihr mich ja scheinbar überlesen habt, wie wär's denn so?
#include <iostream> #include <exception> #include <locale> #include <vector> #include <algorithm> class AlterFalsch : public std::exception { public: const char* what() const throw() { return "Alter in einem ungueltigen Bereich!\n"; } }; class NameFalsch : public std::exception { public: const char* what() const throw() { return "Ein vollstaendiger Name muss\n-Aus Vor- und Nachnahmen bestehen\n" "-Laenger als 3 Zeichen sein\n" "-Darf keine Sonderzeichen enthalten\n"; } }; bool istUmlaut(char c) { const char ae = 132, oe = 148, ue = 129, UE = 220, OE = 214, AE = 196; std::vector<char> sonderzeichen { ae, oe, ue, AE, OE, UE }; return std::find(sonderzeichen.begin(), sonderzeichen.end(), c) != sonderzeichen.end(); } bool nameInOrdnung(const std::string& name) { if(name.size() < 3) return false; unsigned anzahlLeerzeichen = 0; //Ein vollstaendiger Name hat genau 1 Leerzeichen. for(auto i : name) if(!std::isalpha(i, std::locale("")) && !istUmlaut(i)) { if(i == ' ') ++anzahlLeerzeichen; else return false; } if(anzahlLeerzeichen != 1) return false; return true; } bool alterInOrdnung(const int& alter) { return alter <= 150 && alter >= 0; } class Person { int alter; std::string name; public: Person(const std::string& n, int a) : alter(a), name(n) {} Person() : alter(0), name("Unbekannt") {} std::string Name() const { return name; } int Alter() const { return alter; } friend std::istream& operator>>(std::istream& in, Person& p) throw(AlterFalsch); }; std::ostream& operator<<(std::ostream& out, const Person& p) { return out << p.Name() << ", " << p.Alter() << " Jahre alt."; } template<typename typ> void in(typ& para, std::istream& is = std::cin) //wrapper um cin fuer sichere Eingabe { while(!(is >> para)) { std::cerr << "Fehler bei der Eingabe!\n"; is.clear(); is.ignore(1000, '\n'); } } std::istream& operator>>(std::istream& is, Person& p) throw(AlterFalsch) { std::cout << "Name: "; std::getline(is, p.name); if(!nameInOrdnung(p.Name())) throw NameFalsch(); std::cout << "Alter: "; in(p.alter, is); if(!alterInOrdnung(p.Alter())) throw AlterFalsch(); return is; } int main() { Person p; try { std::cin >> p; std::cout << p; } catch(const std::exception& a) { throw; } return 0; }
Aber jetzt ernstgemeinte Fragen:Ist das gut so? (Ich bring mir das selbst nur zum Spaß bei und andere Menschen sehen selten Code von mir, daher die Frage, kann ja sein, dass ich da was falsch gelernt hab vom Stil her). Und ich hab' festgestellt, dass bei
std::isalpha(char, std::locale)mit der Systemlocale auch Umlaute wie ö, ä und ü als false ausgewertet werden und musste mir dann diese blöde istUmlaut schreiben. Warum ist das so, ich dachte die locale wär extra für sowas da?
-
Incocnito schrieb:
Sollte man aber sparsam mit umgehen, da es ja die ganze Datenkapselung durchlöchert.
friend stärkt die Kapslung. Es vermeidet, Member oder Memberfunktionen komplett public zu machen, nur damit irgendeine andere Funktion darauf Zugriff hat.
-
Naja, das kann man so aber nicht stehnlassen.
Besser wäre: Friend schwächt die Datenkapselung nicht so sehr, wie es das Öffentlichmachen von eigentlich privaten Membern macht.
Aber stärken tut sie sie deswegen nicht. Nur weniger schlimm halt.
Und zu viel friend weißt sowieso auf ein schlechtes Design hin.
In der Regel ist es besser, sich bei jedem Verwenden von friend nochmal Gedanken zu machen, ob das überhaupt passieren sollte. In diesem Fall wäre es vllt. besser, der Klasse Person eine Funktion wietoString() constzu verpassen, und der Operator << ruft die dann einfach auf und gibt's aus.
Aber das spielt hier nicht wirklich ne Rolle. In der Realität brauche ich friend so ziemlich gar nicht. Aber ist ja deine Sache.
-
Incocnito schrieb:
In diesem Fall wäre es vllt. besser, der Klasse Person eine Funktion wie
toString() constzu verpassen, und der Operator << ruft die dann einfach auf und gibt's aus.Warum muss ich ein XYZ-Objekt erst in einen String umwandeln, um es ausgeben zu können? Ineffizient.
-
Ja, wär zu viel Aufwand und unnötig, deswegen hab ich ja auch friend verwendet. Ich wollt' nur sagen, dass es (fast?) immer eine Alternative zu friend gibt, die nicht die Datenkapselung schwächt, und die daher zu bevorzugen ist.
War mir hier nur egal und ich wollte ja nur mal zeigen, dass es auch mit friend ginge.
-
Die Alternative wäre eine Funktion print_to(ostream&) :p
friend gewinnt dagegen bei mir, da es kürzer ist.