Konstruktor mit Überprüfung
-
Hallo zusammen mal wieder eine Frage zum Thema Klassen.
Und zwar habe ich einen Standard Konstruktor der Klasse Datum:
Deklaration:
// Standard Konstruktor Datum(const int x=1, const int y=1, const int z=1900);Definition
Datum::Datum(const int x, const int y, const int z) : tag_(x), monat_(y), jahr_(z) { //... return; }Set-Methoden:
// Set-Methoden Definitionen // void Datum::setTag(const int x) {tag_=x; return;} void Datum::setMonat(const int y) {monat_=y; return;} void Datum::setJahr(const int z) {jahr_=z; return;}Ich möchte nun aber ein Datum mit folgenden Werten anlegen:
Datum d3(29,2,2007);Dafür möchte ich aber nicht den Standardkonstruktor aufrufen, sondern einen Konstruktor, der überprüft ob das Datum überhaupt existiert.
Ich habe ein Funktion geschreiben, die ein Datum auf seine Gültigkeit prüft:
bool Datum::isValid() { if (! (1582<= jahr_ ) )//ab aktuelle jahresberechnung return false; if (! (1<= monat_ && monat_<=12) )// 12 monate checken return false; if (! (1<= tag_ && tag_<=31) ) // tage unter 31 liegen return false; if ( (tag_==31) && (monat_==2 || monat_==4 || monat_==6 || monat_==9 || monat_==11) ) // monate die keine 31 tage haben return false; if ( (tag_==30) && (monat_==2) ) // februar hat keine 31 tage return false; if ( (monat_==2) && (tag_==29) && (jahr_%4!=0) ) //februar auf schaltjahr prüfen - kein schaltjahr return false; if ( (monat_==2) && (tag_==29) && (jahr_%400==0) ) //februar auf schaltjahr prüfen - ist schaltjahr return true; if ( (monat_==2) && (tag_==29) && (jahr_%100==0) ) //februar auf schaltjahr prüfen - kein schaltjahr return false; if ( (monat_==2) && (tag_==29) && (jahr_%4==0) ) //februar auf schlatjahr prüfen - ist schaltjahr return true; return true; }Nun meine Fragen:
1. Wie lege ich den Konstruktor an damit der die übergebenen Daten prüft
2. Wenn die Daten nicht richitg sind, soll eine Fehlermeldung ausgegeben werden (ohne Exceptions) und dann soll der Standardkonstruktor aufgerufen werden und das Standard Datum angelegt werden.Ich nehme auch Hinweise entgegen wo so ein Verfahren beschrieben ist. Ich möchte nicht unbedingt die komplette Lösung dafür haben sondern gucken das ich dabei soviel wie möglich lerne.
Vielen Dank.Falls noch Fragen zu Programmteilen bestehen einfach Bescheid sagen.
-
Mir fallen da spontan zwei Möglichkeiten ein.
1. Du erstellst eine statische Factory-Methode
class Datum { static Datum CreateDatum(int d, int m, int y) { if (IsValid(d,m,y) return Datum(d,m,y); PrintErrorMsg(d,m,y); return Datum(); // default } };2. Du integrierst die Prüfung in den Konstruktor:
class Datum { Datum(int d=1, int m=1, int y=1900) { if (!IsValid(d,m,y) { PrintErrorMsg(d,m,y); m_d = 1; m_m = 1; m_y = 1900; } } };
-
1. Wie lege ich den Konstruktor an damit der die übergebenen Daten prüft
Gegenfrage: Was soll passieren, wenn das Datum ungueltig ist?
-
knivil schrieb:
1. Wie lege ich den Konstruktor an damit der die übergebenen Daten prüft
Gegenfrage: Was soll passieren, wenn das Datum ungueltig ist?

Tyle schrieb:
Wenn die Daten nicht richitg sind, soll eine Fehlermeldung ausgegeben werden (ohne Exceptions) und dann soll der Standardkonstruktor aufgerufen werden und das Standard Datum angelegt werden.
-
Also das hat nicht funktioniert:
Konstruktor:
Datum::Datum(unsigned int x, unsigned int y, unsigned int z) { { if (!isValid(x,y,z)) { cout << "Datum ist ungueltig!"; tag_ = 1; monat_ = 1; jahr_ = 1900; } } }Funktion:
bool Datum::isValid(unsigned int tag_, unsigned int monat_, unsigned int jahr_) { if (! (1582<= jahr_ ) )//ab aktuelle jahresberechnung return false; if (! (1<= monat_ && monat_<=12) )// 12 monate checken return false; if (! (1<= tag_ && tag_<=31) ) // tage unter 31 liegen return false; if ( (tag_==31) && (monat_==2 || monat_==4 || monat_==6 || monat_==9 || monat_==11) ) // monate die keine 31 tage haben return false; if ( (tag_==30) && (monat_==2) ) // februar hat keine 31 tage return false; if ( (monat_==2) && (tag_==29) && (jahr_%4!=0) ) //februar auf schaltjahr prüfen - kein schaltjahr return false; if ( (monat_==2) && (tag_==29) && (jahr_%400==0) ) //februar auf schaltjahr prüfen - ist schaltjahr return true; if ( (monat_==2) && (tag_==29) && (jahr_%100==0) ) //februar auf schaltjahr prüfen - kein schaltjahr return false; if ( (monat_==2) && (tag_==29) && (jahr_%4==0) ) //februar auf schlatjahr prüfen - ist schaltjahr return true; return true; }Das Datum wird angelegt, obwohl es nicht angelegt werden dürfte.
Datum:Datum d3(29,2,2007);Wo habe ich den Fehler gemacht?
-
Tyle schrieb:
Wo habe ich den Fehler gemacht?
geh mit dem Debugger durch, dann siehst du es. Deine SOnderbehandlung für den Februar ist inkonsistent zu den anderen Prüfungen.
-
In wiefern inkonsestent? Die Funktion sollte laufen, habe die mal getestet.
-
Zeile 15 und 17 machen keinen Sinn irgendwie.
-
cooky451 schrieb:
Zeile 15 und 17 machen keinen Sinn irgendwie.
Inwiefern?
Edit: Ich würde die Reihenfolge umkehren, aber sonst...?(beziehe mich jetzt nur auf 15 u. 17)
-
Caligulaminus schrieb:
~Edit: Ich würde die Reihenfolge umkehren, aber sonst...? (beziehe mich jetzt nur auf 15 u. 17)~
Und ohne Umkehrung der Reihenfolge ist das ok? Insbesondere bei
Tyle schrieb:
Das Datum wird angelegt, obwohl es nicht angelegt werden dürfte.
Datum:Datum d3(29,2,2007);Wo habe ich den Fehler gemacht?
?
Bist du dir überhaupt sicher, dass eine Umkehrung der Reihenfolge ausreicht?
-
Wenn du die Reihenfolge umkehren würdest dann würde die Ausnahme das Jahre/400 nicht Anwendung finden.
Daher muss doch erst die Ausnahme abgefragt werden.
Alle durch 4 teilbaren Jahreszahlen sind Schaltjahre, aber nicht die durch 100 teilbaren, es sei denn sie sind sogar duch 400 teilbar.
Hier das Testprogramm:
#include <string> #include <iostream> using namespace std; bool checkdate(int m, int d, int y); int main(int argc, char* argv[]) { cout << checkdate( 1, 1, 2005) << endl; // 1=true cout << checkdate( 0, 1, 2005) << endl; // 0=false cout << checkdate(13, 1, 2005) << endl; // 0 cout << checkdate( 2,29, 1992) << endl; // 1 cout << checkdate( 2,29, 1996) << endl; // 1 cout << checkdate( 2,29, 2000) << endl; // 1 cout << checkdate( 2,29, 2001) << endl; // 0 cout << checkdate( 2,29, 2002) << endl; // 0 cout << checkdate( 2,29, 2003) << endl; // 0 cout << checkdate( 2,29, 2004) << endl; // 1 cout << checkdate( 2,29, 2100) << endl; // 0 cout << checkdate( 2,29, 2200) << endl; // 0 cout << checkdate( 2,29, 2300) << endl; // 0 cout << checkdate( 2,29, 2400) << endl; // 1 cout << checkdate( 2,29, 2500) << endl; // 0 system("pause"); return 0; } bool checkdate(int m, int d, int y) { //gregorian dates started in 1582 if (! (1582<= y ) )//comment these 2 lines out if it bothers you return false; if (! (1<= m && m<=12) ) return false; if (! (1<= d && d<=31) ) return false; if ( (d==31) && (m==2 || m==4 || m==6 || m==9 || m==11) ) return false; if ( (d==30) && (m==2) ) return false; if ( (m==2) && (d==29) && (y%4!=0) ) return false; if ( (m==2) && (d==29) && (y%400==0) ) return true; if ( (m==2) && (d==29) && (y%100==0) ) return false; if ( (m==2) && (d==29) && (y%4==0) ) return true; return true; }
-
@SeppJ:
Ich bezog mich auf cookies Aussage:cooky451 schrieb:
Zeile 15 und 17 machen keinen Sinn irgendwie.
Nicht auf die Korrektheit der Funktion insgesamt.
Abgesehen davon habe ich bis jetzt noch keinen echten Fehler gefunden.
(29,2,2007)wird bei mir jedenfalls zurückgewiesen.
-
@Tyle:
Hast recht.
-
Evt. ist etwas anderes im Programm falsch?
Ich verwende ne Methode in der Klasse um die Ausgabe für die Monate in Strings zu konvertieren:
//Zahlen in Monatsdaten konvertieren string Datum::getMonatString() const { switch (monat_) { case 1: return "Januar"; case 2: return "Februar"; case 3: return "Maerz"; case 4: return "April"; case 5: return "Mai"; case 6: return "Juni"; case 7: return "Juli"; case 8: return "August"; case 9: return "September"; case 10: return "Oktober"; case 11: return "November"; case 12: return "Dezember"; default: return "Undefined"; } }Sollte eigentlich nicht das Problem sein, da auch der normale getMonat nicht zurückgewiesen wird.
-
Wenn deine check-Funktion funktioniert und trotzdem (29,2,2007) [jetzt wohl (2,29,2007), da Du die Reihenfolge der Argumente im zweiten Beispiel geändert hast] akzeptiert wird, dann wirst Du sie wohl falsch benutzen.
-
Was macht den der Standardkonstruktor noch außer das Standard Datum anlegen?
Warum zum Beispiel Anstelle von:
if (! (1582<= y ) )nicht:
if ( 1582 > y )?
-
Ja das vermute ich auch.
Hier mal das Programm:
//#include "datum.hpp" //#include "zeit.hpp" //#include "termin.hpp" #include <iostream> #include <string> using namespace std; class Datum { private: //private Variablen Deklaration // unsigned int tag_; unsigned int monat_; unsigned int jahr_; public: // Methoden Deklaration // void setTag(const int); void setMonat(const int); void setJahr(const int); int getTag() const; int getMonat() const; string getMonatString() const; int getJahr() const; // Konstruktor Deklaration // // Standard Konstruktor Datum(const int x=1, const int y=1, const int z=1900); // Überprüfungs Konstruktor Datum(unsigned int, unsigned int, unsigned int); // Überladungs Deklarationen // // Operator << friend ostream &operator<<(ostream &, const Datum &); //Operator >> friend istream &operator>>(istream &, const Datum &); // Operator = Datum& operator=(const Datum &rh); // Operator == bool operator==(const Datum &r); // Operator += Datum &operator+=( int tage); // Methoden(Funktionen) Deklaration bool isValid(unsigned int, unsigned int, unsigned int); void makeValid(); }; // Set-Methoden Definitionen // void Datum::setTag(const int x) {tag_=x; return;} void Datum::setMonat(const int y) {monat_=y; return;} void Datum::setJahr(const int z) {jahr_=z; return;} // Get-Methoden Definitionen // // Tag int Datum::getTag() const { return tag_; } // Monat int Datum::getMonat() const { return monat_; } // Jahr int Datum::getJahr() const { return jahr_; } //Zahlen in Monatsdaten konvertieren string Datum::getMonatString() const { switch (monat_) { case 1: return "Januar"; case 2: return "Februar"; case 3: return "Maerz"; case 4: return "April"; case 5: return "Mai"; case 6: return "Juni"; case 7: return "Juli"; case 8: return "August"; case 9: return "September"; case 10: return "Oktober"; case 11: return "November"; case 12: return "Dezember"; default: return "Undefined"; } } // Konstruktor Definitionen // // Standardkonstruktor Definition Datum::Datum(const int x, const int y, const int z) : tag_(x), monat_(y), jahr_(z) { //... return; } // Konstruktor mit Überprüfung Datum::Datum(unsigned int x, unsigned int y, unsigned int z) { { if (!isValid(x,y,z)) { cout << "Datum ist ungueltig!"; tag_ = 1; monat_ = 1; jahr_ = 1900; } } } // Überladungs Deklarationen // Operator >> istream &operator>>(istream &is, Datum &z) { unsigned int t, m, j; scanf("%i %i %i", &t, &m, &j); z.setTag(t); z.setMonat(m); z.setJahr(j); return is; } // Operator << ostream& operator<<(ostream &os, const Datum &z) { os << z.getTag() << "." <<z.getMonatString() << "."<<z.getJahr(); return os; } // Operator = Datum& Datum::operator=(const Datum &rh) { this->tag_ = rh.tag_; this->monat_ = rh.monat_; this->jahr_ = rh.jahr_; return *this; } bool Datum::operator==(const Datum &r) { return this->getMonat() == r.getMonat() && this->getTag() == r.getTag(); //this->getJahr() == r.getJahr() && //Vergleiche auch Jahreszahlen } // Operator += Datum& Datum::operator+=( int tage) { tag_+= tage; /*if(!isValid()) makeValid();*/ return *this; } bool Datum::isValid(unsigned int tag_, unsigned int monat_, unsigned int jahr_) { if (! (1582<= jahr_ ) )//ab aktuelle jahresberechnung return false; if (! (1<= monat_ && monat_<=12) )// 12 monate checken return false; if (! (1<= tag_ && tag_<=31) ) // tage unter 31 liegen return false; if ( (tag_==31) && (monat_==2 || monat_==4 || monat_==6 || monat_==9 || monat_==11) ) // monate die keine 31 tage haben return false; if ( (tag_==30) && (monat_==2) ) // februar hat keine 31 tage return false; if ( (monat_==2) && (tag_==29) && (jahr_%4!=0) ) //februar auf schaltjahr prüfen - kein schaltjahr return false; if ( (monat_==2) && (tag_==29) && (jahr_%400==0) ) //februar auf schaltjahr prüfen - ist schaltjahr return true; if ( (monat_==2) && (tag_==29) && (jahr_%100==0) ) //februar auf schaltjahr prüfen - kein schaltjahr return false; if ( (monat_==2) && (tag_==29) && (jahr_%4==0) ) //februar auf schlatjahr prüfen - ist schaltjahr return true; return true; } void Datum::makeValid() { // TODO: Implement! } int main() { Datum d1; Datum d2(10,12,2012); cout << "Datum d1: " << d1 << endl; cout << "Datum d2: " << d2 << endl << endl; cout << "Versuche d3 mit Datum 29.02.2007 anzulegen" << endl; Datum d3(29,2,2007); cout << "Datum d3: " << d3 << endl << endl; cout << "Vergleiche d1 mit d2 und d3: " << endl; cout << "d1==d2: " << (d1==d2) << endl; cout << "d1==d3: " << (d1==d3) << endl << endl; cout << "Setze d1 auf Wert von d2" << endl; d1 = d2; cout << "Datum d1: " << d1 << endl << endl; cout << "Addiere 100 Tage zu d1" << endl; d1 += 100; cout << "Datum d1: " << d1 << endl; cout << "Addiere 60 Tage zu d2" << endl; d2 += 60; cout << "Datum d2: " << d2 << endl << endl; cout << "Datum im Format \"tt mm jjjj\" eingeben: "; cout.flush(); cin >> d1; cout << "Speichere eingegebenes Datum in d1" << endl; cout << "Datum d1: " << d1 << endl << endl; system("pause"); return 0; }
-
Warum zum Beispiel Anstelle von:
if (! (1582<= y ) )nicht:
if ( 1582 > y )?
Hat doch den gleichen Effekt

-
Eben. Wenn du eine Fehlermeldung haben möchtest, wenn das Jahr kleiner als 1582 ist, warum prüfst du dann erst ob es größer gleich ist und negierst dann das Ergebnis.
-
Gut die Schreibweise kompliziert das natürlich ändert aber nichts am Verhalten der Funktion.
Ist aber noch die Frage wo ich den Fehler bei der Abfrage gemacht habe

-
Dein Konstruktor
Datum::Datum(unsigned int x, unsigned int y, unsigned int z)wird nicht gerufen, weil 2007, 2 oder 29 alesints sind. Tu den weg, und pack die Überprüfung in deinen StandardkonstruktorDatum(const int x=1, const int y=1, const int z=1900).
Außerdem schreien die vollkommen unsinnigen Bezeichnerx, y, zfür Tag, Monat, Jahr (oder war's jetzt Monat, Tag, Jahr???) nach Verwechslungen. In deinen beiden vorhergehenden Beispielen hattest Du auch zwei verschiedene Reihenfolgen der Argumente.~edit: Typo.~