Nochmal: const und Referenzen



  • Hallo zusammen,
    ich habe nochmal eine Frage bezüglich dem Bezeichner const und Referenzen. Ich dachte eigentlich, dass ich durch eine meiner letzten Fragen es verstanden hätte, doch nun verwirrt mich mein Code wieder.

    Ich habe eine Klasse (MobilePhone), die eine Getter Methode besitzt. Diese sieht so aus:

    const string& getOwner()  const {return owner;};
    

    Diese Methode greift nur lesend auf die Klasse zu (zweites const) und gibt eine konstante Referenz auf "owner" zurück. owner ist ein private Attribut der Klasse.

    Nun dachte ich, dass diese konstante Referenz nicht geändert werden kann. Deswegen führt folgender Code zu einem Fehler:

    string& str = handy.getOwner(); //handy ist eine Instanz meiner Klasse
    

    1.) Liege ich bei folgender Aussage richtig: "str" ist ein Aliasname auf das Attribut, das durch "getOwner" zurückgegeben wird. Da die Rückgabe konstant ist, muss auch der Aliasname (Referenz) konstant sein.

    Folgendes funktioniert aber:

    string str = handy.getOwner(); //handy ist eine Instanz meiner Klasse
    

    2.) Ich erkläre es mir dadurch, dass zwar eine konstante Referenz zurückgegeben wird, doch der Inhalt dieser Referenz wieder in einer eigenständigen Variablen gespeichert wird, die dann nicht konstant sein muss.

    Ist meine Vermutung richtig, warum "str" nicht konstant sein muss oder habe ich das Konzept von "const" immer noch nicht verstanden?

    Vielen Dank
    lg, freakC++



  • Beides richtig. Das Typsystem erzwingt über const lediglich, dass du keinen Schreibzugriff auf das Original bekommst, aber wenn du dir eine Kopie ziehst, kannst du damit natürlich machen, was du willst.



  • Alles klar, dann ist mein Weltbild doch gerettet 😉

    Ich merke mir also: Es geht const also immer um das Element, das als const deklariert worden ist (ist eigentlich auch logisch xD).

    lg, freakC++



  • Warum wird bei solch einer Funktion "int" angenommen und kann daher nicht kompuiliert werden?

    const& unsigned char getR() const {return red;}; //red ist vom Typ unsigned char
    

    Vielen Dank
    lg, freakC++



  • freakC++ schrieb:

    Warum wird bei solch einer Funktion "int" angenommen und kann daher nicht kompuiliert werden?

    const& unsigned char getR() const {return red;}; //red ist vom Typ unsigned char
    

    Vielen Dank
    lg, freakC++

    Versuch es mal so 😉

    const unsigned char& getR() const {return red;}; //red ist vom Typ unsigned char
    


  • ups...peinlich *rotwerd*

    Danke für den Tipp!

    lg, freakC++



  • Da du dich gerade mit const zu befassen scheinst, dachte ich, ich schreib dir da gerade noch etwas dazu.

    Wenn du es schon weißt, ist das ja gut ;-),
    ansonsten schau dir das mal an 😛

    int fkt();
    
    int main()
    {
        fkt() = 1; // error: no-lvalue in assignment
    
        return 0;
    }
    
    /*
        Es wird zwar ganz normal eine Kopie gemacht und diese zurückgegeben,
        die aber per Definition ein r-value ist.
    
        Deswegen kannst du dir das "const" bei retrun-by-value immer sparen,
        da man ja einem r-value sowieso nichts zuweisen kann.
    
        --> Dies gilt aber nur für vordefinierte Datentypen, nicht für abstrakte Datentypen.
    */
    int fkt()
    {
        return 7;
    }
    


  • Danke für die Erklärung. Zwar hätte ich das nie geschrieben, aber deine Erklärung hat mir beim Verständnis nochmal weitergebracht.

    Hier braucht man aber nicht const, doch eine Ausgabe funktioniert trotzdem nicht. Hat das etwas damit zu tun? Ich kann zwar message() wie bei dir etwas zuweisen, doch den statischen String nicht ausgeben. Eigentlich ist es doch so ähnlich wie bei dir, nur dass es funktionieren sollte 😉 .

    #include <iostream>
    using namespace std;
    
    string& message()
    {
    	static string str = "Guten Morgen";
    	return str;
    }
    
    int main()
    {
    	message() = "Guten Abend";
    	string out = message();
    	cout << out << endl;
    }
    

    Danke für deine Hilfe
    lg, freakC++



  • #include <iostream>
    using namespace std;
    
    string& message()
    {
        static string str = "Guten Morgen";
    
        return str;
    }
    
    int main()
    {
        /*
            1.  message() wird aufgerufen und die statische Variable mit "Guten Morgen" initialisiert.
    
            2.  Dann machst du return-by-reference und weißt der statische Variable dann "Guten Abend" zu.
                --> str := "Guten Abend"
    
            3.  Dann rufst du wieder message() auf. 
                Die Initialisierungszeile der statischen Variable wird nicht beachtet.
                Diese Zeile wird nur beim aller ersten Funktionsaufruf ausgeführt, danach immer übersprungen.
                --> str bleibt "Guten Abend" --> out ist somit dann auch "Guten Abend"
        */
        message() = "Guten Abend";
    
        string out = message();
    
        cout << out << endl; // Ausgabe: Guten Abend
    
        cin.sync();
        cin.get();
        return 0;
    }
    


  • Hallo Dweb,
    genau das habe ich ja auch gedacht, doch der Code lässt sich nicht kompilieren. "out" kann icht ausgegeben werden. Stattdessen kommt die folgende Fehlermeldung:

    error C2679: Binärer Operator '<<': Es konnte kein Operator gefunden werden, der einen rechtsseitigen Operanden vom Typ 'std::string' akzeptiert (oder keine geeignete Konvertierung möglich)

    Das verstehe ich nicht, da out doch vom Typ string ist und nur eine Kopie der zurückgegebenen Referenz hat.

    Vielen Dank für die tolle Hilfe
    lg, freakC++



  • #include <string> fehlt.



  • Welchen Compiler hast du?

    Ich hab hier gerade nur "dev-c++" und er meckert gar nicht.



  • Ich stimme dem zu. Inkludiere string.

    Übrigens macht es keinen großen Sinn int, char per Referenz zurückzugeben. Das macht nur Sinn, wenn es sich um komplexe Daten handelt. Zum Beispiel eine std::list. Bei großen Datenmengen kann man so den Aufwand des Kopierens sparen.



  • Oh man...daran lag es. string war echt nich eingebunden. Ich dachte, dass es noch drin war. *grr*, *nochroterwerd*.

    Naja, jetzt läuft es aber!

    Bis dann
    lg, freakC++


Anmelden zum Antworten