Kopien, Referenzen, Zeiger



  • Hallo,

    was ist eigentlich genau der Unterschied zwischen folgenden Arten von Class-Membern:

    class B {...}

    class A
    {
    private:
    B m_b1;
    B& m_b2;
    B* m_b3;

    public:
    ...
    }

    Also rein speichertechnisch weiß ich etwa den Unterschied, nur hab ich noch nicht ganz verstanden, was das programmtechnisch für einen Unterschied macht.

    Also WANN (für welche Problemstellung) sollte man Kopie, Referenz oder Zeiger verwenden?



  • zB:

    #include <iostream>
    
    using namespace std;
    
    int mul2_copy( int value )
    {
        return value * 2;
    }
    
    void mul2_ref( int &value )
    {
        value *= 2;
    }
    
    void mul2_array( int *value, size_t num )
    {
        for( size_t i = 0; i < num; ++i )
            value[ i ] *= 2;
    }
    
    int main( )
    {
        cout << mul2_copy( 2 ) << endl;
    
        int value = 2;
        mul2_ref( value );
        cout << value << endl;
    
        int values[ ] = { 1, 2, 3, 4, 5, 6 };
        mul2_array( values, 6 );
    
        for( int i = 0; i < 6; ++i )
            cout << values[ i ] << " ";
        cout << endl;
    }
    

    Greetz, Swordfish



  • Hm, ja soweit ist mir das klar, aber um noch einmal auf meine Problemstellung zurückzukommen:

    Stell dir vor, du hast eine Aggregation, und zwar eine 1:1 Beziehung.

    Eine Klasse A HAT eine Klasse B als Membervariable.

    Würdest du diese Membervariable als einfache Kopie, als Referenz oder als Zeiger speichern?

    (Vielleicht sollte deine Antwort ja genau diese Frage beantworten, und ich habe sie nur nicht richtig verstanden) 😉

    danke.



  • Das kann man pauschal so nicht beantworten. Das kommt darauf an, was du damit machen möchtest. Eine Referenz scheint am wenigsten geeignet.

    Greetz, Swordfish



  • Beispiel:

    Eine Klasse 'Haus' hat als Member ein Objekt der Klasse 'Tuer'.

    Das Haus besitzt eine Methode zum Ändern der Höhe der Tuer.

    etwa so:

    class Haus
    {
    private:
       Tuer m_tuer; //oder als Zeiger?
    
    public:
       Haus(const Tuer& tuer) :m_tuer(tuer)
       {
       }
       void setHeighOfTuer(int x)
       {
          m_tuer.setHeight(x);
       }
    };
    

    (die Klasse Tuer hab ich mir geschenkt)

    Beide Objekte der Klasse Haus und Tuer sollen zur Laufzeit in 'main' erstellt werden. Etwa so:

    Tuer t;
    Haus h(t);
    h.setHeight(2);

    Habe ich es richtig verstanden, dass, wenn die Membervaribale m_tuer ein Zeider oder eine Referenz wäre, dass Objekt 't' veäbdert würde, im meinem obigen Falle jedoch nur eine Kopie und nicht die Membervaribale selbst verändert würde?



  • sly schrieb:

    Habe ich es richtig verstanden, dass, wenn die Membervaribale m_tuer ein Zeider oder eine Referenz wäre, dass Objekt 't' veäbdert würde, im meinem obigen Falle jedoch nur eine Kopie und nicht die Membervaribale selbst verändert würde?

    Ja.

    Wobei ich dein Beispiel für nicht gerade für sinnhaft im sinne der OOP halte.

    Greetz, Swordfish



  • Wenn du Membervariablen zu Referenzen machst, musst du aufpassen, dass keiner Unsinn damit macht. Also am besten lässt du das, es sei denn es ist absolut nötig.



  • Swordfish schrieb:

    Wobei ich dein Beispiel für nicht gerade für sinnhaft im sinne der OOP halte.

    Ich weiß. 😉

    War auch nur ein simples Beispiel für die generelle Situation:

    eine Klasse A braucht zur Erledigung ihrer Aufgabe ein Objekt der Klasse B, und muss den Zustand dieses Objekts speichern...

    Oder ist DAS in deinen Augen auch unsinnig im Sinne der OOP?



  • sly schrieb:

    Beispiel:

    Eine Klasse 'Haus' hat als Member ein Objekt der Klasse 'Tuer'.

    Das Haus besitzt eine Methode zum Ändern der Höhe der Tuer.

    etwa so:

    class Haus
    {
    private:
       Tuer m_tuer; //oder als Zeiger?
    
    public:
       Haus(const Tuer& tuer) :m_tuer(tuer)
       {
       }
       void setHeighOfTuer(int x)
       {
          m_tuer.setHeight(x);
       }
    };
    

    (die Klasse Tuer hab ich mir geschenkt)

    Beide Objekte der Klasse Haus und Tuer sollen zur Laufzeit in 'main' erstellt werden. Etwa so:

    Tuer t;
    Haus h(t);
    h.setHeight(2);

    Habe ich es richtig verstanden, dass, wenn die Membervaribale m_tuer ein Zeider oder eine Referenz wäre, dass Objekt 't' veäbdert würde, im meinem obigen Falle jedoch nur eine Kopie und nicht die Membervaribale selbst verändert würde?

    Der entscheidende Begriff ist dabei "Ownership": Hat die Tür (also genau das Exemplar) auch außerhalb des Hauses eine Existenzberechtigung/Funktion/Aufgabe/Leben/... ?
    Ja : Pointer/Referenz (ggf. const)
    Nein: Unterobjekt

    Ist nur eine grobe Regel für die erste Entscheidung; es gibt viele Spezialfälle, in denen man davon abweicht, aber zur ersten Orientierung hilt's erstmal.
    Anders ausgedürckt: "Gehört" die Tür dem Haus ? Wenn ja, dann sollte es die auch selbst kapseln, nur selbst verwalten (d.h. private Attribut halten, nur Kopien/const-Referenzen rausgeben und Manipulationen nur über über Zugriffsfunktionen zulassen). => Die Tür wird mit dem Haus geboren und stirbt mit ihm. (Falls das Haus seine Tür(en) überleben muß, bleibt Dir in C++ nichts anderes übrig als trotzdem einen Pointer oder einen Container zu verwenden ... aber das ist eine der o.g. Ausnahmen).

    Hat sie jedoch nur "Anteil an der Tür", würde ich dem Haus auch nur eine (const)-Referenz oder einen (const)-Pointer zugestehen. Damit kann dem Haus eine beliebige Tür (z.B. auch eine Spezialisierung wie "Holztür" oder "Stahltür") zugewiesen werden.

    Gruß,

    Simon2.



  • Danke, das bringt mich schon mal weiter. Das war worauf meine Frage abzielte.



  • 1. Fall
    Nehmen wir an es gäbe 2 Fussballvereine, die sich einen Platz teilen.

    In solch einem Fall würdest du einen Zeiger auf einen solchen Platz als Membervariable definieren.

    2. Fall

    Gehört der Platz dem Verein selbst würdest du die Membervariable vom Typ Platz definieren (layering)



  • kuerbis schrieb:

    2. Fall
    Gehört der Platz dem Verein selbst würdest du die Membervariable vom Typ Platz definieren (layering)

    gehörte jedem verein genau ein platz, würde ich zuerst an layering denken.


Anmelden zum Antworten