Ich versuche mich an einer Container-Klasse



  • Aber wenn ich die Schleife nicht mache, bleiben primitive Typen uninitialisiert. Das will ich unbedingt vermeiden.



  • verwende operator new (size_t) oder einen allokator und dann algorithmen wie uninitialized_fill, um dir mal einen anhaltspunkt zu geben.



  • Andere Frage (hat nichts mit dem davor zu tun):
    Kann ich von std::vector ableiten, um den operator[] zu redefinieren?

    template<class _Ty, class _Ax = allocator<_Ty> > class Array
    : public std::vector<class _Ty, class _Ax = allocator<_Ty> >
    {
    };
    

    Offensichtlich stört sich der Compiler an der zweiten Template-Argumentenliste. Aber ohne Argumentenliste nach std::vector geht es auch nicht.



  • Hallo,
    std::vector ist nicht als öffentliche Basisklasse gedacht.

    template<class _Ty, class _Ax = allocator<_Ty> > class Array 
    : public std::vector<class _Ty, class _Ax = allocator<_Ty> > 
    { 
    };
    

    Das ist syntaktischer Käse. So wäre's richtig:

    #include <vector>
    template<class _Ty, class _Ax = std::allocator<_Ty> > class Array 
    : public std::vector<_Ty, _Ax> 
    { 
    };
    

    Aber noch einmal, nur für den Fall, dass das Kurzzeitgedächtnis bereits geleert wurde, std::vector ist nicht als öffentliche Basisklasse gedacht und auch nicht als solche geeignet.



  • template<class _Ty, class _Ax = allocator<_Ty> > class Array
    : public std::vector<_Ty,_Ax> //Du willst ja von einem konkreten Vektor erben (geht ja nicht anders)
    {
    };
    

    Namen, die mit Unterstrich beginnen, sind reserviert. Lieber nicht verwenden.



  • HumeSikkins schrieb:

    Aber noch einmal, nur für den Fall, dass das Kurzzeitgedächtnis bereits geleert wurde, std::vector ist nicht als öffentliche Basisklasse gedacht und auch nicht als solche geeignet.

    Was ist daran schlecht, bzw. (weil ich dir das jetzt einfach mal glaube) welche anderen Möglichkeiten habe ich, um den operator[] zu redefinieren?
    Ich will, dass er Indexsicher ist.

    EDIT: Die abgeleitete Klasse scheint auch nicht zu funktionieren:

    Array<int> blubb(10);
    

    error C2664: 'Array<_Ty>::Array(const Array<_Ty> &)': Konvertierung des Parameters 1 von 'int' in 'const Array<_Ty> &' nicht möglich
    with
    [
    _Ty=int
    ]
    and
    [
    _Ty=int
    ]
    Ursache: Konvertierung von 'int' in 'const Array<_Ty>' nicht möglich
    with
    [
    _Ty=int
    ]



  • Optimizer schrieb:

    HumeSikkins schrieb:

    Aber noch einmal, nur für den Fall, dass das Kurzzeitgedächtnis bereits geleert wurde, std::vector ist nicht als öffentliche Basisklasse gedacht und auch nicht als solche geeignet.

    Was ist daran schlecht, bzw. (weil ich dir das jetzt einfach mal glaube) welche anderen Möglichkeiten habe ich, um den operator[] zu redefinieren?

    std::vector ist keine gute öffentliche Basisklasse, da vector keine virtuellen Methoden und insbesondere keinen virtuellen Destruktor besizt. Es ist also zum einen nicht sinnvoll möglich ein abgeleitetes Objekt über eine Basisklassenreferenz anzusprechen (der eigentliche Grund für öffentliche Vererbung) und zum anderen kannst du sogar undefiniertes Verhalten heraufbeschwören, nämlich genau dann, wenn du ein dynamisch erzeugtes Objekt über eine Basisklassenreferenz löschst.

    Leitest du öffentliche von std::vector ab, so missbrauchst du die öffentliche Vererbung als Mittel zur simplen Codewiederverwendung (des Codes der Basisklasse). Und das ist eine Sache die man tunlichst vermeiden sollte.

    Die einzige saubere Möglichkeit ist Containment.

    template <class T>
    class Array
    {
    private:
    std::vector<int> impl_;
    public:
    // Interface das du brauchst forwarded zu impl_
    };
    

    Für schreibfaule (keine gute Motivation) mag auch private-Vererbung noch ok sein.



  • Hei, noch nie probiert mit privater Vererbung zu verhindern das ein Objekt auf einen Basiszeiger landen kann.

    Wenn das im Standard definiert ist (nehme ich an , sonst würdest es nich schreiben... 🤡)) => thx 🤡



  • Knuddlbaer schrieb:

    Hei, noch nie probiert mit privater Vererbung zu verhindern das ein Objekt auf einen Basiszeiger landen kann.

    Wenn das im Standard definiert ist (nehme ich an , sonst würdest es nich schreiben... 🤡)) => thx 🤡

    du kannst trotzdem (über umweg) einen zeiger auf die basisklasse bekommen. aber als nicht-friend-nicht-klassenmember eigentlich keine gefahr 😉



  • Für schreibfaule (keine gute Motivation) mag auch private-Vererbung noch ok sein.

    Warum? Was ist denn an private-Vererbung schlechter als an einer Membervariable? 🙄

    Kommt das nicht aufs Gleiche raus?



  • Optimizer schrieb:

    welche anderen Möglichkeiten habe ich, um den operator[] zu redefinieren?

    Einfach ein assert() im operator[] einfügen?
    Es ist ja nicht verboten die Library zu ändern.

    IMHO ist dies die beste Lösung - denn von value Typen zu erben bringt oft mehr Probleme als Vorteile.



  • @davi

    Wie denn ? Mein Compiler sagt mir bei bisherigen Versuchen das eine Umwandlung zwar vorhanden ist, aber nicht darauf zugegriffen werden kann.

    @Shade

    Ändern an der Lib ist nicht verboten aber unsinnig. Es wäre nicht mehr portabel.



  • Knuddlbaer schrieb:

    Ändern an der Lib ist nicht verboten aber unsinnig. Es wäre nicht mehr portabel.

    Wieso? es geht nicht um Funktionalität sondern um ein assert.
    Da bleibt alles portabel 🙂 Denn wenn das assert fehlt, ändert sich das Programmverhalten nicht sonderlich.



  • Knuddlbaer schrieb:

    @davi
    Wie denn ? Mein Compiler sagt mir bei bisherigen Versuchen das eine Umwandlung zwar vorhanden ist, aber nicht darauf zugegriffen werden kann.

    class private_base {
    public: 
       void foo () { cout << "foo\n"; }
    };
    
    class derived : private_base {
       friend int main();
    };
    
    int main () {
       derived d;
       d.foo();
    }
    


  • Ahja, thx



  • @Knuddlbaer
    Oder die gute alte Hacker-Schule:

    class Base
    {};
    
    class Derived : private Base
    {};
    
    int main()
    {
        Derived d;
        Base& b = (Base&)d;
    }
    

    Böser C-Cast! Hält sich nicht an Access-Level. Pfui!

    Warum? Was ist denn an private-Vererbung schlechter als an einer Membervariable?

    Z.B. das man mehr Abhängigkeiten hat.



  • @Hume: Meinst du das so, wie du es geschrieben hast? Dann ist doch meine Klasse nur noch für ints. Ich will natürlich genau die selbe Flexibilität, die vector hat.

    template <class T> 
    class Array 
    { 
    private: 
    std::vector<int> impl_; 
    public: 
    // Interface das du brauchst forwarded zu impl_ 
    };
    

    @Shade: Da hab ich zuviele Skrupel, die Lib zu ändern. Ich könnte mir höchstens vorstellen, die Header zu kopieren, umzubenennen und mit (minimalen Änderungen) dann meine eigene Klasse zu haben. 😕
    Dann wäre mir aber Veerbung gleich lieber.

    Kann ich von Klassen-Templates jetzt nicht erben? Oder muss ich den Konstruktor redefinieren?



  • Was spricht denn gegen:

    template <class T> 
    class Array 
    { 
    private: 
    std::vector<T> impl_; 
    public: 
    // Interface das du brauchst forwarded zu impl_ 
    };
    


  • < Blödsinn >



  • Optimizer schrieb:

    @Hume: Meinst du das so, wie du es geschrieben hast?

    Nein. Statt int sollte da natürlich eigentlich T stehen. Mein Fehler.

    Kann ich von Klassen-Templates jetzt nicht erben?

    Natürlich kannst du grundsätzlich von Klassen-Templates erben. Es ist aber niemals eine gute Idee öffentlich von Value-Klassen zu erben. Unabhängig davon ob das nun Template-Klassen sind oder normale.

    Oder muss ich den Konstruktor redefinieren?

    Wie meinen? Konstruktoren werden grundsätzlich nicht vererbt. Auch das ist unabhängig von Template-Klassen.


Anmelden zum Antworten