Klassen als Member, Pointer oder nicht, Programmierstil?



  • Hi,
    mal an prinzipielle Frage: Wenn ich Klassen als Member von übergeordneten Klassen habe, gibt es da Kriterien, ob diese als Pointer oder direkt als Membervariablen zu verwenden sind?
    Z.B.

    class A {
    public:
      A(int _init) : wert(_init) 
      {}
      bool b();
    privat:
      init wert;
    };
    
    class B {
    public:
      B(int init);
      ~B() {
         if (pA) delete pA;
      }
      foo() {
         pA = new A(123);
         pA->b();
      }
    private:
      A *pA;
    };
    

    oder so:

    class A {
    public:
      A();
      void init(int _init);
      bool b();
    privat:
      ...
    };
    
    class B {
    public:
      B(int init);
    private:
      foo() {
         a.init(123);
         a.b();
      }
      A a;
    };
    

    Im zweiten Fall kann ich ja nicht über den Konstruktor initialisieren, brauche also eine init()-Methode. Im ersten Fall instantiiere ich die Klasse erst bei der Verwendung und kann sie dann über den Konstruktor initialisieren, muss mich aber später auch um das "delete" kümmern.
    Was ist zu bevorzugen? Ist es eine reine Stilfrage oder gibt es klare Kriterien, wann was zu verwenden ist?
    Danke und Gruß!



  • Member bzw. Komposition bedeutet "hat ein".
    Pointer bedeutet "kennt ein".

    Bzgl. Deiner These mit init(), google mal nach initialisierungsliste.



  • fu06 schrieb:

    Im zweiten Fall kann ich ja nicht über den Konstruktor initialisieren, [...]

    Warum nicht ... ?

    Wennschon pointer, warum nicht smarte?



  • Das funktioniert so eigentlich problemlos: http://ideone.com/2Uy7jZ
    Aber trotzdem fragt man sich, ob das ein durchdachtes Design ist. Auf Anhieb fällt mir nichts ein, wo das sinnvoll sein könnte.



  • OK, ich vergass zu sagen, dass ich von C komme und C++ Umsteiger bin...
    😉

    Swordfish schrieb:

    fu06 schrieb:

    Im zweiten Fall kann ich ja nicht über den Konstruktor initialisieren, [...]

    Warum nicht ... ?

    OK, Denkfehler... mir war unklar, wie ich "a" hier initialisieren soll. Es muss also über die Initialisierungsliste von B erfolgen:

    class A {
    public:
      A(int _init) : c(_init)
      {}
      void b(void) {
        // ...
      }
    private:
      int c;
    };
    
    class B {
    public:
        B(int _init) : c(_init), a(123)
        {
        }
    private:
      void foo(void) {
         a.b();
      }
      A a;
      int c;
    };
    

    bzw. A hat einen Standardkonstruktor ohne Parameter für default-Initalisierungen.

    Ist das korrekt?



  • fu06 schrieb:

    class B {
    public:
      B(int _init) : c(_init), a(123)
      {
      }
      // ...
      A a;
      int c;
    };
    

    Obacht, dass a vor c im C'tor von B initialisiert wird.
    Die Reihenfolge in der Initialisierungsliste ist belanglos. Entscheidend ist die Reihenfolge in der Klassendefinition.



  • fu06 schrieb:

    bzw. A hat einen Standardkonstruktor ohne Parameter für default-Initalisierungen.

    Deine Fragen sind etwas wirr... A hat hier definitiv keinen Defaultkonstruktor. Ob einer Sinn macht, kommt auf den Kontext an. Das Objekt selbst sollte nach Ausführung des Konstruktors in einem definierten Zustand bzw. "lebensfähig" sein, ohne dass neue Maßnahmen ergriffen werden müssen. Aber was das genau heißt, ist wiederrum eine andere Frage. Ich denke z.B. dass ein Container oder ein Array nicht dafür zuständig ist seine Elemente zu null-initialisieren. Aber natürlich sollte es allen seinen Membern sinnvolle Werte zuweisen. (Größe, etwaige Pointer, etc.)



  • cooky451 schrieb:

    fu06 schrieb:

    bzw. A hat einen Standardkonstruktor ohne Parameter für default-Initalisierungen.

    Deine Fragen sind etwas wirr... A hat hier definitiv keinen Defaultkonstruktor. Ob einer Sinn macht, kommt auf den Kontext an. Das Objekt selbst sollte nach Ausführung des Konstruktors in einem definierten Zustand bzw. "lebensfähig" sein, ohne dass neue Maßnahmen ergriffen werden müssen. Aber was das genau heißt, ist wiederrum eine andere Frage. Ich denke z.B. dass ein Container oder ein Array nicht dafür zuständig ist seine Elemente zu null-initialisieren. Aber natürlich sollte es allen seinen Membern sinnvolle Werte zuweisen. (Größe, etwaige Pointer, etc.)

    OK, den Defaultkonstruktor habe ich nicht ins Codebeispiel aufgenommen. Und er wird nicht autom. erzeugt, wenn ein anderer deklariert wurde.

    Hier nochmal das Beispiel komplett:

    class A {
    public:
      A(int _init) : c(_init)
      {}
      A(): c(0)
      {}
      void b(void) {
        // ...
      }
    private:
      int c;
    };
    
    class B {
    public:
        B(int _init) : c(_init), a(123)
        {
        }
    private:
      void foo(void) {
         a.b();
      }
      A a;
      int c;
    };
    

    Dann kann ich A irgendwo anders auch parameterlos instatiieren. Für B brauche ich es ja nicht, da B::a erst dann erzeugt wird, wenn ein B-Objekt erzeugt wird. Und dies erfolgt immer durch den B(int) Konstruktor, der den A(int) Kontruktor aufruft.
    Falls ich was Falsches sage, bitte ich um Korrekturen...



  • Warum nicht einfach

    A(int init_ = 0)
    

    ? 😉
    Abgesehen davon ist der Unterstrich am Anfang einer Variable recht unbeliebt, weil man damit nah an reservierten Bezeichnern ist.



  • Pointer machen ja nur die App unsicher. Besser die Finger von lassen.



  • addt schrieb:

    Pointer machen ja nur die App unsicher. Besser die Finger von lassen.

    das ist der grösste schwachsinn den ich seit langem gelesen habe. und das mit abstand...

    fährst du auto?
    wenn ja, tanken macht das fahren gefährlicher.


Anmelden zum Antworten