Klassenvariable als Referenz, Objekt oder Zeiger?



  • Hallo zusammen,

    ich bin mir nicht ganz im Klaren, ob das geht, was ich andenke und was das Beste unter C++ ist?

    Ich habe ja die Möglichkeit eine Klassenvariable als Objekt anzulegen:

    Object object;
    

    oder als Zeiger:

    Object *object;
    

    Im zweiten Fall lege ich object mit new an und lösche es (z.B. im Destruktor) mittels delete.
    Wie sieht das im ersten Fall aus? Da kann object z.B. im Konstruktor oder ggf. über Initialisierungsliste initialisieren, aber wann wird es zerstört?

    Welche der Methoden ist ressourcenschonender, effizienter und schneller?

    Gibt es die Möglichkeit eine Klassenvariable als Referenz anzulegen und in der Initialisierungsliste zu initialisieren, also etwa so:

    Object& object;
    
    Konstruktor() : object(Object())
    ...
    

    Denke eher nicht?!

    Danke schon mal
    Ciao



  • Reth schrieb:

    Hallo zusammen,

    ich bin mir nicht ganz im Klaren, ob das geht, was ich andenke und was das Beste unter C++ ist?

    Ich habe ja die Möglichkeit eine Klassenvariable als Objekt anzulegen:

    Object object;
    

    oder als Zeiger:

    Object *object;
    

    Im zweiten Fall lege ich object mit new an und lösche es (z.B. im Destruktor) mittels delete.
    Wie sieht das im ersten Fall aus? Da kann object z.B. im Konstruktor oder ggf. über Initialisierungsliste initialisieren, aber wann wird es zerstört?

    Wenn es den Gültigkeitsbereich verlässt, also z.B. wenn das erstellende Objekte zerstört wird.

    Welche der Methoden ist ressourcenschonender, effizienter und schneller?

    Bei der Zeiger variante haste einen Zeiger mehr, also benutz am besten Referenzen bzw. die normale Methode wenn du keinen Zeiger brauchst. Aber das macht nicht viel aus, also kannst Zeiger ruhig benutzen.

    Gibt es die Möglichkeit eine Klassenvariable als Referenz anzulegen und in der Initialisierungsliste zu initialisieren, also etwa so:

    Object& object;
    
    Konstruktor() : object(Object())
    ...
    

    Denke eher nicht?!

    Nein, das geht nicht.

    mfg.



  • Wenn du eine Referenz anlegst, mußt du sie sofort auf eine vorhandene Variable verlinken, sonst bekommst du deinen Code nicht durch den Compiler:

    Object gOb;
    
    ...
    int something()
    {
      Object& myOb=gOb;//Referenz auf das globale Objekt
      ...
    }
    

    (dabei ist es wichtig zu beachten, daß die Referenz nicht länger lebt als das referenzierte Objekt)

    Bei Pointern mußt du dich selber darum kümmern, daß sie ordnungsgemäß wieder freigegeben werden (genau ein mal UND mit der richtigen Funktion (da gibt es in C++ mindestens drei verschiedene ;)).



  • CStoll schrieb:

    Bei Pointern mußt du dich selber darum kümmern, daß sie ordnungsgemäß wieder freigegeben werden (genau ein mal UND mit der richtigen Funktion (da gibt es in C++ mindestens drei verschiedene ;)).

    Welche sind das denn? Referenzzählung, shared pointer oder andere?

    Habe gerade noch ein anderes Problem mit Referenzen:

    Ich habe eine Klasse A, die in einer Methode eine Referenz auf eines ihrer Member B zurückgibt.
    Diese Methode wird von einer Klasse C gerufen, in der B überhaupt nicht bekannt gemacht ist (mit include). Nun meldet mir der Linker vom G++ undefined reference beim Linken der Klasse C.
    Das Ganze sieht ungefähr so aus:

    //Klasse A
    #include "B"
    
    class A
    {
        B b;
    
        B& getB( return b);
    }
    
    ...
    // Klasse C
    #include A
    
    class C
    {
        void do(A& a)
        {
            a.getB().doBStuff();
        }
    }
    

    Muss ich in C die Klasse B inkludieren?



  • Reth schrieb:

    CStoll schrieb:

    Bei Pointern mußt du dich selber darum kümmern, daß sie ordnungsgemäß wieder freigegeben werden (genau ein mal UND mit der richtigen Funktion (da gibt es in C++ mindestens drei verschiedene ;)).

    Welche sind das denn? Referenzzählung, shared pointer oder andere?

    Nein - delete (für new), delete[] (für new[]) und free() (für malloc()). Je nachdem, womit du den Speicher reserviert hast, mußt du die dazu passende Freigabefunktion aufrufen.

    Habe gerade noch ein anderes Problem mit Referenzen:

    Ich habe eine Klasse A, die in einer Methode eine Referenz auf eines ihrer Member B zurückgibt.
    Diese Methode wird von einer Klasse C gerufen, in der B überhaupt nicht bekannt gemacht ist (mit include). Nun meldet mir der Linker vom G++ undefined reference beim Linken der Klasse C.
    Das Ganze sieht ungefähr so aus:

    //Klasse A
    #include "B"
    
    class A
    {
        B b;
    
        B& getB( return b);
    }
    
    ...
    // Klasse C
    #include A
    
    class C
    {
        void do(A& a)
        {
            a.getB().doBStuff();
        }
    }
    

    Muss ich in C die Klasse B inkludieren?

    Also irgendwas stimmt an deinem Beispiel nicht. Erstens ist A::getB privat (d.h. C darf das überhaupt nicht verwenden), zweitens erwartet die angegebene Methode einen Parameter vom Typ "return" (dürfte sich als Syntax-Fehler bemerkbar machen) und drittens fehlt der Funktionskopf.



  • O weh, da war ich gestern Abend wohl schon zu müde.
    Sollte auch nur Pseudocode sein, also ich probiers nochmal:

    //Klasse A
    #include "B"
    
    class A
    {
        privat:
            B b;
    
        public:
            B& getB() { return b; }
    }
    
    ...
    // Klasse C
    #include A
    
    class C
    {
        public:
            void do(A& a)
            {
                a.getB().doBStuff();
            }
    }
    

    So, hoffe nun ist es ersichtlicher, was ich meine! 🙂

    Nochmal zu den Freigabemöglichkeiten (delete, free etc.): Da hab ich in ne falsche Richtung gedacht, und zwar wie man Objekte sicher freigibt, auf die mehrere Zeiger in versch. anderen Objekten zeigen.



  • Und welche Funktion findet der Linke nun nicht? (die Klassendefinition von B müsste bekannt sein, da "B.h" indirekt über "A.h" eingebunden wurde - aber natürlich mußt du die zugehörige "B.cpp" auch mit compilieren und einlinken)

    Reth schrieb:

    Nochmal zu den Freigabemöglichkeiten (delete, free etc.): Da hab ich in ne falsche Richtung gedacht, und zwar wie man Objekte sicher freigibt, auf die mehrere Zeiger in versch. anderen Objekten zeigen.

    Da mußt du jemanden finden, der die Zuständigkeit für das Löschen übernimmt - sprich: Smart-Pointer. (ich denke mal, einer der Boost-Pointer dürfte das richtige für dich sein - außer du willst da unbedingt etwas eigenes entwickeln)



  • CStoll schrieb:

    Und welche Funktion findet der Linke nun nicht? (die Klassendefinition von B müsste bekannt sein, da "B.h" indirekt über "A.h" eingebunden wurde - aber natürlich mußt du die zugehörige "B.cpp" auch mit compilieren und einlinken)

    Also alle Klassen sind korrekt in den make-Prozess eingebunden, werden gelinkt und compiliert (war schon zuvor so, die beschriebene Funktionalität ist eine Erweiterung dieser Klassen).

    Wenn es nun zum Linken des Executables kommt, in das dann alle Objektdateien einfliessen, meint ld sinngemäß:

    Undefined Reference in class C at class B::doBStuff()

    Wie gesagt, funktionierten die Klassen A, B und C aber bisher im Buildprozess immer, solange ich diese Aufrufkombination noch nicht implementiert hatte (die Methoden und Klassen waren in der Form aber schon vorhanden, nur der Aufruf in Klasse C auf die Methode in B ist neu).



  • Es lag wohl an der Art der Implementierung von B, die auf Header und Source verteilt war und bei make nicht zusätzlich angegeben wurde.

    Habe das nun geändert und es sieht besser aus, habe aber noch kein endgültiges Ergebnis!

    Jop, das wars wohl!



  • Referenz macht wenig Sinn, da man das Objekt an der Stelle dann auch mit new anlegen und mit delete löschen müsste. Ansonsten hat man eine Referenz auf ein nach dem Beenden des Konstruktors gelöschten Objekts.
    Ich würde immer erste einmal versuchen das Objekt selbst zu halten und keinen Zeiger, denn das bedeutet immer weniger Aufwand und ist nicht so fehleranfällig.
    Ein Zeiger hält man sich nur dann wenn es notwendig ist, also wenn das gehaltene Objekt nicht kopiert werden soll, wenn das Objekt über eine Schnittstelle gehalten wird und von einem abgeleiteten Typ sein kann, ....



  • Leider kann ich hier nicht mit einer Kopie des Objektes arbeiten, so dass ich auf einen Zeiger oder eine Referenz angewiesen bin.


Anmelden zum Antworten