const-Methoden



  • Hi,

    ich dachte... ich hätte das Konzept verstanden. Soweit ich weiß dürfen in const-Methoden keine Membervariablen verändert werden u. aus diesem Grund auch keine (nicht-const)Methoden aufgerufen werden.

    Jetzt scheint es aber noch eine andere Eigenart zu geben. Der Compiler spuckt mir hier folgende Fehlermeldung (an den fett markieren stellen im Code) aus:

    error C2440: 'return': 'const float [2]' kann nicht in 'float *const ' konvertiert werden

    [code="cpp"]
    class Grundstueck {
    private:
    float Ecke1[2];
    float Ecke2[2];
    public:
    Grundstueck(float x1=0,float y1=0,float x2=0, float y2=0);
    float * const get_Ecke1() const;
    float * const get_Ecke2() const;
    ...

    };

    Grundstueck::Grundstueck(float x1, float y1, float x2, float y2){
    Ecke1[0]=x1; Ecke1[1]=y1;
    Ecke2[0]=x2; Ecke2[1]=y2;
    }
    float * const Grundstueck::get_Ecke1() const{
    return Ecke1;
    }
    float * const Grundstueck::get_Ecke2() const{
    return Ecke2;
    }

    [/code]

    Kann mir einer erklären was hier genau passiert ?



  • Da darfst du nur ein const float zurückgeben, ansonsten kann man die Membervariable über den Zeiger verändern, was dann nicht der Sinn der Sache einer const-Methode ist.



  • Außerdem wäre eine Point-Klasse o. ä. hier angebracht, die einen einzelnen Punkt repräsentiert. Vielleicht boost::tuple oder std::pair.



  • Wobei sich die Fehlermeldung darauf bezieht, daß float * const und float const * (alias const float * ) verschiedene Dinge sind.



  • Du gibst dort ein "const pointer to float" zurück, du solltest aber ein "pointer to const float" zurückgeben. (const float* bzw. float const*, nicht aber float *const. Pointer zeigen immer auf den Typen links vom 😉



  • Irgendwie stehe ich jetzt total auf dem Schlauch... ich bin gerade ein bisschen am testen.

    Ich hab das ganze jetzt erstmal so belassen:

    float * const Grundstueck::get_Ecke1(){
    	return Ecke1;
    }
    

    Hier gebe ich ja einen konstanten Zeiger auf meinen float Member zurück... nehmen wir mal an ich wöllte diesen Zeiger manipulieren (was hier nicht funktionieren sollte). Wie würde ich das überhaupt anstellen? So wie ich es kenne landet der zurückgegebene Wert in einer neuen Variablen z.B.

    float * p;
    p=g.get_Ecke1();
    p=p+1;
    

    Damit wäre das ganze doch hinfällig 😕



  • Nein, du verstehst es nicht. Lies meinen Beitrag noch mal genau. Dass man den Pointer verändern kann, interessiert niemanden, weil es nichts in der Klasse ändert. Das hier

    struct foo
    {
      int i_;
    
      int bar() const
      {
        return i_;
      }
    };
    

    Ist auch kein Problem, auch wenn das int nicht const ist. Aber wer das int verändert, verändert nichts am Objekt. Du brauchst also, wie schon geschrieben, keinen konstanten Pointer, sondern einen Pointer auf ein konstantes Objekt.



  • John D schrieb:

    Ich hab das ganze jetzt erstmal so belassen

    Und somit bleibt der Fehler wie er ist ist...

    Dein return paßt nicht zur Signatur deiner Methode.



  • Hm...

    ok d.h. schonmal.... in dieser Variante hat das "const" keinen praktischen Nutzen?

    typ * const bsp(){
        ...
    }
    


  • Nein. Genau so wie

    const int foo();
    

    Nicht besonders sinnvoll ist.



  • John D schrieb:

    in dieser Variante hat das "const" keinen praktischen Nutzen?

    Nicht nur hat es keinen Nutzen, es wird vollkommen ignoriert.

    typ * const bsp();
    

    ist genau die gleiche Signatur wie

    typ * volatile bsp();
    

    und

    typ * bsp();
    


  • Sehr gut... sehr gut

    Ich habe gerade mal vollkommen auf das "const" verzichtet und über den Pointer den Member verändert.

    Wundert mich nur, das unser Dozent diesen getter in der Musterlösung auch ohne "const" definiert hat:

    C++:
    class Grundstueck {
    private:
    float Ecke1[2];
    float Ecke2[2];

    Das bricht doch mit der Kapselung oder liege ich da falsch?



  • da hat was gefehlt:

    class Grundstueck {
    private:
    	 float Ecke1[2];
    	 float Ecke2[2];   
    public:
    	Grundstueck(float x1=0,float y1=0,
    			   float x2=0, float y2=0);
    	float *get_Ecke1();
    	float *get_Ecke2();
    	void set_Ecke1(float, float);
    	void set_Ecke2(float, float);
        float Flaeche();
    };
    


  • Ob es die Kapselung bricht ist wohl Ansichtssache, aber in jedem Fall sind die Setter so leicht sinnlos. 😉



  • Jep 😉

    Ich denke ich habs verstanden. Danke dir/euch.


  • Mod

    praktiker schrieb:

    John D schrieb:

    in dieser Variante hat das "const" keinen praktischen Nutzen?

    Nicht nur hat es keinen Nutzen, es wird vollkommen ignoriert.

    typ * const bsp();
    

    ist genau die gleiche Signatur wie

    typ * volatile bsp();
    

    und

    typ * bsp();
    

    nein. Das sind durch aus unterschiedliche Signaturen. Top-level cv-Qualifikation wird nur bei Parametern ignoriert.
    Allerdings geht ein cv-Qualifikation des Rückgabetyps beim Funktionsaufruf verloren, wenn dieser Typ ein Skalar ist.



  • Ob es die Kapselung bricht ist wohl Ansichtssache

    Ähh, es bricht eindeutig die Kapselung. Die Funktion get_Ecke1() ist wohl das Paradebeispiel wie man es nicht machen sollte. Damit kann man herliche Sauereien wie folgendes machen:

    int main ()
    {
      Grundstueck g;
      float* f;
    
      f = g.get_Ecke1();
      *f = 1;
      f++;
      *f = 2;
      // Och woher weis ich denn dass ein Grundstück keine 3D Punkte als Grenze hat ?
      f++;
      *f = 3;
      // Och wir wollen aber double Koordinaten setzen 
      double* f2;
      f2 = (double*) g.get_Ecke1();
      *f2 = 5;
    }
    

    Effetive C++ Regel:
    1.) Baue deine Klassen so dass sie einfach zu bedienen aber schwer zu missbrauchen sind.
    2.) Gebe niemals eine Referenz, ein Zeiger auf interne Dinge zurück, wenn es eine Kopie auch tut.



  • Noch eine Schweinerei ist mir da eingefallen.

    int main ()
    {
      Grundstueck* g = new Grundstueck;
      float* f;
    
      f = g->get_Ecke1();
      delete g;
      *f = 1;
      f++;
    }
    


  • cooky451 schrieb:

    C++ ist auch scheiße, guck mal!

    *((void*)0)
    

    Das kompiliert auch nicht.



  • @Bitte ein Bit
    Es ist immer noch Schwachsinn, auch wenn ein Mod den Beitrag gelöscht hat.

    @komplimat
    Ja, es geht um's Prinzip.



  • cooky451 schrieb:

    Es ist immer noch Schwachsinn, auch wenn ein Mod den Beitrag gelöscht hat.

    Den Satz verstehe ich nicht. Gelöschten Beitrag? Schwachsinn? Häh??? 😕

    Was spricht gegen folgendes?

    Point Grundstueck::get_Ecke2() const;
    

Anmelden zum Antworten