Konstruktorliste



  • Hi Leute!

    Ich hab diese Klasse hier nun geschrieben:

    class Bruch
    {
    private:
    	int zaehler;
    	int nenner;
    
    public:
    	Bruch(int z, int n) : zaehler(z), nenner(n)		//Konstruktor
    	{
    		if(n == 0)
    		{
    			nenner = 1;
    		}
    	}
    
    	double bruchAusrechnen()
    	{
    		return (double)(zaehler/nenner);
    	}
    
    	int getZaehler()
    	{
    		return zaehler;
    	}
    
    	int getNenner()
    	{
    		return nenner;
    	}
    
    	void setZaehler(int varZaehler)
    	{
    		zaehler = varZaehler;
    	}
    
    	void setNenner(int varNenner)
    	{
    		if(varNenner != 0)
    		{
    			nenner = varNenner;
    		}
    		else
    		{
    			cout << "Nenner sollte gleich Null gesetzt werden... Ich setze gleich 1!";
    			nenner = 1;
    		}
    	}
    };
    

    Ich hab hier nun ein paar Fragen zu meiner Konstruktorliste. Laut meinem Compiler funktioniert der Code soweit. Mir ist aber nicht klar, warum man eine Konstruktorliste überhaupt verwenden soll. Man könnte bspw. auch so schreiben

    Bruch(int zaehler, int nenner){...}
    

    anstatt so

    Bruch(int z, int n) : zaehler(z), nenner(n){...}
    

    . Warum wurden, von der Syntax her gesehen, bei der eigentlichen Konstruktorliste Klammern gewählt? Was ich damit meine: zaehler(z). Das "zaehler" korrelliert ja mit der Membervariable zaehler. Der Wert der von der main-Funktion dann an den Konstruktor übergeben wird, steht also erstmal in zaehler und wird dann an das "z" des Konstruktors durchgereicht, oder? Stimmt das soweit? Man könnte also sagen, es ist eine Variable. Warum muss ich da dann immer eine Klammer schreiben? Klammern bringe ich von Grund auf mit Funktionen in Verbindung. Aber, zaehler(z) ist ja keine Funktion in dem Sinn, oder?

    Könnt ihr mir helfen?



  • In der Liste werden deine Member konstruiert...
    Konstruktoren sind Funktionen...
    :xmas1:



  • vip@r schrieb:

    return (double)(zaehler/nenner);
    

    Das tut nucht das, was Du willst. Es ist immer noch eine normale Ganzzahldivision, da du nur das Divisionsergebnis explizit zu double konvertierst, nicht aber einen der beiden Operanden.

    vip@r schrieb:

    Mir ist aber nicht klar, warum man eine Konstruktorliste überhaupt verwenden soll.

    Dort werden die Datenelemente initialisiert. Bei Datentypen wie int oder double ist das allerdings nicht so wichtig. Da kannst Du sie auch nachträglich im Konstruktor setzen wobei sie vorher einen nicht definierten Wert haben. Es gibt aber auch Datentypen (z.B. Klassen), die selbst Konstruktoren haben und über einen solchen Konstruktor initialisiert werden müssen. Deine Bruch-Klasse ist sogar ein Beispiel davon. Ein Objekt Deiner Bruchklasse muss über den Konstruktor, der 2 ints bekommt, initialisiert werden:

    class SonstWas {
      Bruch b;
    public:
      SonstWas()
      : b(23,42)
      {}
    }
    

    Und das hier

    class SonstWas {
      Bruch b;
    public:
      SonstWas()
      { b = Bruch(23,42); }
    }
    

    würde nicht kompilieren, weil b initialisiert werden muss bevor der Code in den {} Klammern ausgeführt wird. Das kann aber nicht funkionieren, da Bruch keinen Default-Konstruktor hat und der Compiler auch nicht weiß, woher die 2 ints kommen sollen, mit denen b initialisiert werden soll.

    Die Art der Initialisierung mit den Klammern nennt man "direkte Initialisierung". Das ist genau dasselbe wie das hier:

    Bruch x (23,42); // direkte Initialisierung
    

    Ja, es sieht wie ein Funktionsaufruf aus. Ist es ja auch irgendwie -- zumindest ein "Konstruktoraufruf" und ein Konstruktor ist so etwas ähnliches wie eine Funktion. Sie gibt nur nichts zurück und hat auch keinen eigenen Namen.

    Cheers!
    kk



  • Davon abgesehen finde ich eine Überprüfung des Nenners auf 0 für unnötig. Und die Zuweisung so gar für falsch.
    Biete doch lieber eine freie Funktion an:

    bool is_nan(const Bruch& value)
    {
      return value.get_nenner() == 0;
    }
    

    wenn dir so ist, als ob vor einer rechenoperation geprüft werden sollte, kannst du die funktion dort aufrufen und eine fehlermeldung (evtl. nur im debugmode) ausgeben, es korrigieren oder dich einfach gar nicht darum kümmern.
    wenn ich 2 integer dividieren will, muss ich den divisor auch auf 0 prüfen, wenn ich nicht möchte, dass da was schief geht.

    bb



  • Wenn, dann mach doch gleich einen statischen Member:

    static const Bruch NaN(0, 0);
    


  • 314159265358979 schrieb:

    Wenn, dann mach doch gleich einen statischen Member:

    static const Bruch NaN(0, 0);
    

    Quark, mal wieder, leider.

    Dann zahlste ganz ohne Not im op== drauf.



  • ???



  • 314159265358979 schrieb:

    Wenn, dann mach doch gleich einen statischen Member:

    static const Bruch NaN(0, 0);
    

    Ich würde sowas gar nicht erst zulassen. Finde es sehr fragwürdig was der Threadsteller da macht wenn ich 0 als Nenner übergebe. An solchen Stellen sollte man nicht versuchen Logik-Fehler auszumerzen, sondern knallhart nen Fehler werfen.



  • 314159265358979 schrieb:

    Wenn, dann mach doch gleich einen statischen Member:

    static const Bruch NaN(0, 0);
    

    und dann hat man was gekonnt?
    op== kann man nicht nehmen, weil dort (außer bei sonderfällen) zaehler und nenner übereinstimmen müssen, NaN ists aber immer, wenn der nenner 0 ist.



  • Ich vesteh eure Einwände überhaupt nicht.



  • 314159265358979 schrieb:

    Ich vesteh eure Einwände überhaupt nicht.

    dann zeig mal genau, was du mit dem statischen member vor hast.



  • Was soll ich denn groß damit vorhaben? Ist das nicht offensichtlich?



  • 314159265358979 schrieb:

    Was soll ich denn groß damit vorhaben? Ist das nicht offensichtlich?

    entweder du hast nen denkfehler oder bisher hat einfach niemand erkannt, wie toll dein super vorschlag ist, weil es doch nicht so offensichtlich ist.



  • 314159265358979 schrieb:

    ???

    Der Bruch ist genau dann NaN, wenn sein Nenner 0 ist. Du zahlst im operator== drauf, weil du nicht mehr einfach Nenner und Zähler auf Gleichheit prüfen kannst, sondern du ihn so oder ähnlich implementieren musst:

    bool operator== (Bruch lhs, Bruch rhs)
    {
       return lhs.nenner() == 0 && rhs.nenner() == 0 // beide NaN
           || lhs.nenner() == rhs.nenner() && lhs.zaehler() == rhs.zaehler();
    }
    

    Davon abgesehen, dass zwei NaNs nie gleich sind...



  • Danke Leute!

    Ihr habt mir doch einiges weitergeholfen! Das Problem was ich mit der Konstruktorliste hatte, hab ich soweit beseitigt.

    Danke!


Anmelden zum Antworten