const member und operator=



  • "const" heißt, daß das Element nicht geändert werden kann. Da kannst du dich noch so sehr auf den Kopf stellen, der Compiler lässt dich diesen Wert nicht mehr ändern.

    (aber eigentlich sollte der obere Ausschnitt so funktionieren - der braucht nicht den op=, sondern den Copy-Ctor (und der funktioniert mit const-Membern)).



  • Jaja, aber wie kann ich denn eine Membervariable einführen, die sich nach Erzeugung NIE mehr ändert? Die z.B. von der Konstellation der im Konstruktor übergebenen Parameter abhängt?

    Mal als doofes Beispiel das Geschlecht einer Klasse Person. Wenn man Geschlechtsumwandlungen zunächst einmal nicht zulässt, gibt's entweder Jungens oder Mädchen. Und wenn Mutter und Vater auf die Idee kommen, ein neues Objekt zu (er)zeugen, hätte das im Konstruktor z.B. nen Parameter Geschlecht. Die Membervariable könnte und sollte folglich const sein. Aber dann kann ich das Kind nichtmehr irgendwie zuweisen.

    Zugegeben, das hinkt etwas bei Personen und Kindern, aber ist klar, was ich meine??



  • Sorry, der Beitrag bezog sich auf GPC. Da war ich wohl beim schreiben zu langsam



  • Hmm, bei mir klappt das nicht. Allerdings auch mit nem struct. liegt's daran? Ich muss wohl mal ein größeres Beispiel geben:

    typedef struct _CurvatureInfo
    {
        const float       MinPrincipalCurvature;
    
        _CurvatureInfo(const float   minPrincipalCurvature = 0.0f)
            : MinPrincipalCurvature(minPrincipalCurvature)
        {
        };
    }CurvatureInfo;
    
    // ...
    
    class CUtils
    {
    public:
        inline static CurvatureInfo CreateCurvature(/* some parameters */)
        {
            // some calculations
            return CurvatureInfo(calculatedValue);
        };
    };
    
    // ....
    // SomeClass.cpp
    
    void SomeClass::method()
    {
        //...
        CurvatureInfo* curvatures = new CurvatureInfo[num];
    
        for(int i = 0; i < num; i++)
        {
            curvatures[i] = CUtils::CreateCurvature(/* the parameters */);
        }
    }
    

    Puh. Und in der for-Schleife mault der Compiler. Ich hoffe, der Code ist schlüssig. Habe ihn ziemlich zusammengestutzt.



  • Also entweder du setzt dein Attribut als Pseudo-Konstante (d.h. du sorgst dafür, daß niemand bewußt den Wert ändert) oder du lebst damit, die Objekte nicht zuweisen zu können (es macht ja auch wenig Sinn, einen existierenden Menschen zu überschrieben - und genau das wäre die Semantik hinter dem op=) und reichst nur Zeiger auf deine Objekte herum.

    Edit: Und bei deinem Code-Beispiel wäre es eine gute Idee, STL-Container zu verwenden (und per push_back() mit Werten zu füllen).



  • FelixManke schrieb:

    Jaja, aber wie kann ich denn eine Membervariable einführen, die sich nach Erzeugung NIE mehr ändert? Die z.B. von der Konstellation der im Konstruktor übergebenen Parameter abhängt?

    Mit const ändert sich nie was.

    Um auf dein Beispiel zu verweisen:

    class Person {
    public:
      enum Geschlecht {M, W};
    
    private:
      const Geschlecht g;
    
      //Keine Zuweisungen möglich
      Person& operator=(const Person&);
    
    public:
      Person(Geschlecht g_) : g(g_) {}  // Ctor
      Person(const Person &p) : g(p.g) {}  //Copy Ctor
      ~Person();  //Dtor
    
      Geschlecht getGeschlecht() const { return g; }
    };
    
    //...
    
    Person me(Person::M);  //Männlich
    Person you(me);  //ebenfalls männlich, über Copy Ctor
    
    Person x(Person::W);
    you = x;  //nix da, op= gesperrt, Geschlechtsumwandlungen sind böse.
    

    Klaro? 🙂

    MfG

    GPC



  • Du kannst durchaus auch const member haben. Du musst sie nur zum richtigen Zeitpunkt (Konstruktor) initialisieren:

    CPerson.h:

    #include <string>
    
    class CPerson
    {
    private:
        const int m_geschlecht;
        std::string m_name;
    public:
        CPerson(int Geschlecht, std::string Name);
        int getGeschlecht();
        std::string &getName();
    
    };
    

    CPerson.cpp:

    #include "CPerson.h"
    
    CPerson::CPerson(int Geschlecht, std::string Name):
    m_geschlecht(Geschlecht),
    m_name(Name)
    {
     // All in initalizers   
    }
    
    int CPerson::getGeschlecht()
    {
        return m_geschlecht;
    }
    
    std::string &CPerson::getName()
    {
        return m_name;
    }
    

    Main.cpp:

    #include "CPerson.h"
    #include <iostream>
    
    int main(int argc, char **argv)
    {
        int dummy = 0;
        CPerson Sohn(1, "Peter");
        CPerson Tocher(0, "Marianne");
    
        std::cout << "Sohn Name: " << Sohn.getName() 
            << " Geschlecht: " << Sohn.getGeschlecht() << std::endl;
        std::cout << "Tocher Name: " << Tocher.getName() 
            << " Geschlecht: " << Tocher.getGeschlecht() << std::endl;
        std::cin >> dummy;
    }
    


  • Hmm, aber wie mache ich das in meinem konkreten Fall? Ich kann da ja schlecht einen Copy-Konstruktor benutzen, wenn ich das Ergebnis einfach von einer Methode entgegennehme. Und nen anderen Konstruktor kann ich auch nicht aufrufen.



  • Noch mal zur genaueren Erklärung:

    curvatures[i] = CUtils::CreateCurvature(/* the parameters */);
    

    Hier wird intern der Zuweisungsoperator (=) deiner Klasse aufgerufen.
    Da diese aber ein konstantes Member enthält, kannst du diesen Operator ja nicht verwenden (und der Compiler erzeugt auch keine Default-Implementation hierfür).

    Wenn du wirklich diese konstante Member behalten willst, mußt du mit Zeigern arbeiten, d.h. z.B.

    inline static CurvatureInfo* CreateCurvature(/* some parameters */)
        {
            // some calculations
            return new CurvatureInfo(calculatedValue); // <-- hier new verwenden
        };
    
    CurvatureInfo** curvatures = new CurvatureInfo*[num];
    
    for(int i = 0; i < num; i++)
    {
        curvatures[i] = CUtils::CreateCurvature(/* the parameters */);
    }
    

    Und beim Zerstören des Arrays, dann

    for(int i = 0; i < num; i++)
    {
        delete curvatures[i];
    }
    delete [] curvatures;
    


  • Ok, Danke. Aber wenn Pointer und Heap die einzige Möglichkeit sind, lasse ich das const vielleicht einfach weg -- macht die Sache einfacher :-).



  • FelixManke schrieb:

    Hmm, aber wie mache ich das in meinem konkreten Fall? Ich kann da ja schlecht einen Copy-Konstruktor benutzen, wenn ich das Ergebnis einfach von einer Methode entgegennehme. Und nen anderen Konstruktor kann ich auch nicht aufrufen.

    Natürlich kannst du:

    class Person {
      //wie oben
    };
    
    Person foo() {
      Person p(Person::M);
      return p;
    }
    
    Person x = foo();
    

    Klappt doch 🙂

    MfG

    GPC



  • Das ist doch, sofern ich richtig schaue, derselbe Code, wie in meinem echten Beispiel mit der Curvature.

    Ne Klasse (Person bzw. CurvatureInfo) mit nem const Member,
    nen Konstruktor, wo dieser Member initialisiert wird,
    ne Methode (einer anderen Klasse - foo() bzw. CUtils::CreateCurvature()), die ein neues Objekt erzeugt und
    ne (lokale) Variable (einer dritten Klasse), die dieses Objekt empfängt (Person x bzw. curvatures[i]).

    Warum klappt das denn bei mir nicht?



  • FelixManke schrieb:

    Das ist doch, sofern ich richtig schaue, derselbe Code, wie in meinem echten Beispiel mit der Curvature.

    Keine Ahnung, hab deinen Code nicht gelesen.

    Ne Klasse (Person bzw. CurvatureInfo) mit nem const Member,
    nen Konstruktor, wo dieser Member initialisiert wird,

    nem Copy-Ctor und nem privat deklarierten op=.

    Die Person x wird per Copy-Ctor mit dem Objekt, welches foo zurückgibt, initalisiert. Scharf, heh? 😉

    MfG

    GPC



  • Oh sorry,

    da habe ich vorhin nicht genau genug geguckt und das mit dem operator= übersehen 🙄. Sorry.

    Scharf ist's wirklich. Wieso gibt sich denn der Compiler plötzlich damit zufrieden, wenn er GAR keinen Zuweisungsoperator mehr hat. Wie kommt der denn auf die Idee, plötzlich den Copy-Konstruktor zu nehmen?! Sonderbar....



  • Hallo GPC,

    dein Beispiel entspricht aber nicht dem von FelixManke,
    da du den Copy-Konstruktor bei "Person x = foo()" aufrufst, während
    wie ich auch schon geschrieben habe, bei FelixManke's Programm der Zuweisungsoperator aufgerufen wird, d.h.

    Person x;
    x = foo();
    

    wird auch NICHT funktionieren!!!



  • Th schrieb:

    Hallo GPC,

    dein Beispiel entspricht aber nicht dem von FelixManke,

    behauptete ich ja auch nicht 😉

    da du den Copy-Konstruktor bei "Person x = foo()" aufrufst, während
    wie ich auch schon geschrieben habe, bei FelixManke's Programm der Zuweisungsoperator aufgerufen wird, d.h.

    Person x;
    x = foo();
    

    wird auch NICHT funktionieren!!!

    korrekt...

    FelixManke schrieb:

    Scharf ist's wirklich. Wieso gibt sich denn der Compiler plötzlich damit zufrieden, wenn er GAR keinen Zuweisungsoperator mehr hat. Wie kommt der denn auf die Idee, plötzlich den Copy-Konstruktor zu nehmen?! Sonderbar....

    ...dazu folgendes Beispiel:

    std::string s("");  //Ctor
    
    std::string s2(s);  //Copy-Ctor
    std::string s3 = s;  //Copy-Ctor, oha.
    
    std::string s4;
    s4 = s;  //Zuweisungs operator
    

    MfG

    GPC


Anmelden zum Antworten