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)


  • Mod

    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 😕


Anmelden zum Antworten