Zuweisungoperator in vererbter templateklasse



  • Hallo,

    eine kurze Frage (Hilfe hat nichts gebracht). Ich habe eine Template klasse, sowie eine vererbte klasse dieser. Nun weiß ich ja dass Konstruktoren, Destruktoren und Zuweisungsoperator nicht mit vererbt werden.

    Wenn ich nun den Zuweisungsoperator in der abgeleiteten template klasse implementiere, muss ich dann auch die private members der Basisklasse da zuweisen oder wird der Zuweisungsoperator von der Basisklasse automatisch auch aufgerufen? Oder muss ich ihn vielleicht explizit dann selber aufrufen?

    Danke bereits
    Sam



  • Katachi schrieb:

    muss ich dann auch die private members der Basisklasse da zuweisen

    Nein, kannst du nicht. Auf private Member der Basisklasse hast du keinen Zugriff in der abgeleiteten Klasse.

    oder wird der Zuweisungsoperator von der Basisklasse automatisch auch aufgerufen?

    Nur wenn du den kompletten Zuweisungsoperator der neuen Klasse automatisch vom Compiler generieren lässt, d.h. wenn dir Elementweise Zuweisung reicht.

    Oder muss ich ihn vielleicht explizit dann selber aufrufen?

    Wenn du op= in der abgeleiteten Klasse selber implementierst ja.

    class Base
    {
      /* member... */
    public:
      Base& operator= (Base const& rhs);
    };
    
    class Derived
    {
      int member1;
      std::string member2;
    public:
      Derived& operator= (Derived const& rhs)
      {
        Base::operator=(rhs);
        member1 = rhs.member1;
        member2 = rhs.member2;
        std::cout << "Abgesehn von diesem cout hätte auch der ganze op= compilergeneriert werden koennen!" << std::endl;
        return *this;
      }
    };
    


  • Selber aufrufen. Oder aber die Finger von Vererbung (für diesen Fall) lassen. Wofür willst Du Vererbung nutzen? Ich kann micht nicht daran erinnern, in einer abgeleiteten Klasse jemals operator= einer Basisklasse aufgerufen zu haben. Das klingt verdächtig.



  • pumuckl: Vielen Dank! Sorry, ging um protected members nicht private. Natürlich kein Zugriff auf private. 🙂 Danke auch für die Erläuterungen!

    Sebastian: die Basisklasse beinhaltet daten die eine Zuweisung benötigen. Jedoch gibt es auch neue Daten in der abgeleiteten Klasse die ebenfalls Zuweisungen benötigen. Deshalb der Zuweisungsoperatoraufruf beider Klassen.



  • Katachi schrieb:

    Sebastian: die Basisklasse beinhaltet daten die eine Zuweisung benötigen. Jedoch gibt es auch neue Daten in der abgeleiteten Klasse die ebenfalls Zuweisungen benötigen.

    Ja und?

    Entweder weißt Du nicht, dass Kopierkonstruktor, Zuweisung und Destruktor automatisch generiert werden können (falls möglich) oder Du machst etwas falsch, wenn Du benutzerdefinierte Versionen brauchst (Stichworte "Kapselung", "RAII", etc).

    Gruß,
    SP



  • Sebastian Pizer schrieb:

    Ja und?

    Entweder weißt Du nicht, dass Kopierkonstruktor, Zuweisung und Destruktor automatisch generiert werden können (falls möglich) oder Du machst etwas falsch, wenn Du benutzerdefinierte Versionen brauchst (Stichworte "Kapselung", "RAII", etc).

    Sorry, versteh ich jetzt nicht ganz was das jetzt damit zu tun hat. Wie würdest du es denn machen?

    Hier mal eine vergleichbare Testklassen (natürlich nur mit den zum Verständnis nötigen Stuff):

    template<typename T>
    Base<T>
    {
      Base(const int cnt) : _vc(cnt) { values = bNew T[_vc]; }
      Base<T> &operator=(const Base<T>& rhs)
      {
       for(int i = 0; i < _vc; ++i) values[i] = rhs(i);
       return *this;
      }
    
      protected:
        int _vc;
        T *values;
    };
    
    template<typename T>
    Derived<T> : public Base<T>
    {
     Derived(const int cnt, const float dim) : Base<T>(cnt), test(dim) {}
    
     protected:
       NClass test;
    };
    

    Beispiel:

    Derived<float> a(20,400);
    Derived<float> b(20,500);
    [...]
    a = b;
    

    So, wie würdest du es denn jetzt machen (Derived::test und Base::values müssen aktualisiert werden)? Ich bin immer bereit etwas zu lernen. Oder meint ihr einfach dass der entsprechende zuweisungsoperator sowieso vom compiler erzeugt wird?

    Danke schonmal



  • Das mit den Unterstrichen am Anfang von Bezeichnern ist nicht gut, weil viele solcher Bezeichner "reserviert" sind.

    Wofür ist denn die Vererbung da?

    Katachi schrieb:

    Wie würdest du es denn machen?

    Kommt drauf an, was Du damit anstellen willst. Vielleicht so:

    template<class T>
    class dings {
      std::vector<T> bums;
      NClass test;
    public:
      dings(int i1, int i2) : bums(i1), test(i2) {}
    };
    

    Katachi schrieb:

    Oder meint ihr einfach dass der entsprechende zuweisungsoperator sowieso vom compiler erzeugt wird?

    Ich bin der Meinung, dass die Resourcen-Verwaltung auf einen relativ kleinen Fetzen Code reduziert werden sollte (hier durch std::vector gelöst) und dass man sich vorher genau überlegen sollte, ob Komposition statt Vererbung nicht vielleicht angebrachter wäre.

    Gruß,
    SP



  • Sebastian Pizer schrieb:

    Das mit den Unterstrichen am Anfang von Bezeichnern ist nicht gut, weil viele solcher Bezeichner "reserviert" sind.

    Guter Tipp.

    Sebastian Pizer schrieb:

    Wofür ist denn die Vererbung da?
    Kommt drauf an, was Du damit anstellen willst.

    Die Basisklasse ist eine dreidimensionale Datenstruktur. Diese speichert hauptsächlich einen Datenwert auf den man mit bestimmten Routinen zugreifen kann. Dies reicht für viele, einfache Operationen. Andere Operationen mit der Datenstruktur benötigen aber noch zusätzliche Routinen und zuätzliche Daten. Da kommt dann die erweiterte abgeleitete Klasse ins Spiel. Es greift auf die gleichen Daten zu, aber erlaubt höherrangige Routinen darauf zuzugreifen und Dinge zu berechnen. Die zusätzlichen Daten brauchen aber auch zusätzlichen Speicher. Deswegen ist es für mich nur ratsam mit Vererbung zu arbeiten. So kann ich die Objekte der Basisklasse für einfache Operationen verwenden (weniger Speicherverbrauch, schnellere Erzeugung der Objekte durch weniger Vorkalkulatinen im Konstruktor, und natürlich weniger Konstruktoraufrufe von den zusätzlichen Daten) und die abgeleitete Klasse für höherrangige Aufgaben.
    Würde ich das alles einbetten, dann würde ich für die meisten Aufgaben unnötigen Speicher alloziieren und berechnungen durchführen die Performancelastig sind.

    Vererbung zeigt für mich hier den genau richtigen Nutzen. Oder was würdest du sagen?


Log in to reply