pointer auf list von Basisklasse/Abgeleitete Klasse



  • DrakoXP schrieb:

    Das ist generell undefiniert...

    Was problemlos klappen müsste (wenn deine Klassen polymorph sind, also virtuelle Methoden usw. verwenden), wäre das:

    std::list<klasse *> * p1;
    //...
    std::list<A *> * p2 = static_cast<std::list<A *> *>(p1);
    

    Das sollte funktionieren, da in der Liste dann auch nur Zeiger gespeichert sind.
    Allerdings zeugen solche Konstrukte nicht gerade von gutem Design.

    Bingo. Natürlich kann ich bei Vererbung nur pointer, nicht statisch gespeicherte Klassen ineinander casten... 🙄

    Vielleicht solltest du uns lieber mal erklären, wofür du das brauchst...

    Naja ich hab ja mehrere list< klasse >, über die ich iterieren will.
    Statt für jeden Typ eine schleife zu shcreiben möchte ich eine schleife für alle Typen schreiben, und elemente per Basisklassenpointer ansprechen.



  • Vesuchs mal mit einer Templatefunktion.



  • Kontrasubjekt schrieb:

    Naja ich hab ja mehrere list< klasse >, über die ich iterieren will.
    Statt für jeden Typ eine schleife zu shcreiben möchte ich eine schleife für alle Typen schreiben, und elemente per Basisklassenpointer ansprechen.

    Folgende Möglichkeiten:

    a) Du packst statt der einzelnen Klassen Pointer auf A (oder 😎 in eine Liste und iterierst darüber. Ob ggf. eine ptr_list angemessen ist oder ob du shared_ptr/unique_ptr oder andere smarte Dinge in deiner Liste speicherst musst du selbst entscheiden, die Speicherverwaltungs-Frage wird auf jeden Fall ein Thema sein.

    b) Du definierst einen Sammelcontainer, der die 10 verschiedenen Listen enthält. Dazu eine Iteratorklasse, die beim Dereferenzieren ein A& (oder B&) zurückgibt und automatisch beim Inkrement von (ListX.end()-1) nach (ListY.begin()) springt.

    a) dürfte das Gewollte sein, ist zumindest der "normalere" Fall. Da du dein problem aber so überaus allgemein beschrieben hast, kann man da auch nicht viel mehr zu sagen.



  • Vesuchs mal mit einer Templatefunktion.

    hab ich temporär eine gebaut die die Schleife über die elemente enthält, hilft in meinem Fall nur wenig, weil ich diesen hässlichen block gleich an 4 stellen im code stehen hab.

    switch(this->cur_item->entity_type())
                {
                    case dfts::section: { dfts::deselect_all<f_section>(*reinterpret_cast<const std::list<f_section>*>(this->cur_item->get_data()), *this->main_wnd.f_viewer); }
                    break;
                    case dfts::part: { dfts::deselect_all<f_part>(*reinterpret_cast<const std::list<f_part>*>(this->cur_item->get_data()), *this->main_wnd.f_viewer); }
                    break;
                    case dfts::room: { dfts::deselect_all<f_room>(*reinterpret_cast<const std::list<f_room>*>(this->cur_item->get_data()), *this->main_wnd.f_viewer); }
                    break;
                    case dfts::cases: { dfts::deselect_all<f_case>(*reinterpret_cast<const std::list<f_case>*>(this->cur_item->get_data()), *this->main_wnd.f_viewer); }
                    break;
                    case dfts::margin: { dfts::deselect_all<f_margin>(*reinterpret_cast<const std::list<f_margin>*>(this->cur_item->get_data()), *this->main_wnd.f_viewer); }
                    break;
                    case dfts::weight: { dfts::deselect_all<f_weight>(*reinterpret_cast<const std::list<f_weight>*>(this->cur_item->get_data()), *this->main_wnd.f_viewer); }
                    break;
                    case dfts::loadcase: { dfts::deselect_all<f_loadcase>(*reinterpret_cast<const std::list<f_loadcase>*>(this->cur_item->get_data()), *this->main_wnd.f_viewer); }
                    break;
                    case dfts::plane: { dfts::deselect_all<f_plane>(*reinterpret_cast<const std::list<f_plane>*>(this->cur_item->get_data()), *this->main_wnd.f_viewer); }
                    break;
                    case dfts::tank: { dfts::deselect_all<f_tank>(*reinterpret_cast<const std::list<f_tank>*>(this->cur_item->get_data()), *this->main_wnd.f_viewer); }
                    break;
                    case dfts::hole: { dfts::deselect_all<f_hole>(*reinterpret_cast<const std::list<f_hole>*>(this->cur_item->get_data()), *this->main_wnd.f_viewer); }
                    break;
                    case dfts::stepdata: { dfts::deselect_all<step_data>(*reinterpret_cast<const std::list<step_data>*>(this->cur_item->get_data()), *this->main_wnd.f_viewer); }
                    break;
                }
    

    @pumuckl:
    b) ist fancy, aber mehr als nötig.
    a) scheint mir ebenfalls die beste Lösung zu sein. Danke für den Hinweis.



  • "Hässlich" ist noch stark untertrieben.

    Vielleicht hilft Dir noch der double dispatch bzw das visitor pattern.

    Wie gesagt: Dass Du diesen Kram 4mal im Code stehen hast, ist natürlich Käse. Das ist 4mal zu viel. Don't repeat yourself. Und undefiniertes Verhalten ist natürlich auch Pfui.



  • Kontrasubjekt schrieb:

    Vesuchs mal mit einer Templatefunktion.

    [...]

    Irgendwie hatte ich da an etwas weniger kompliziertes gedacht:

    //die Tamplatefunktion
    template<typename T>
    void list_loop(std::list<T> & l)
    {
        typedef typename std::list<T>::iterator iter_t;
        for(iter_t i(l.begin()), end(l.end()); i != end; ++i)
        {
            element_op(*i);
        }
    }
    
    //deine Basisklasse A
    struct A
    {
        virtual void print() = 0;
        virtual ~A(){}
    };
    
    //die gewuenschte Operation auf die Basisklassenobjekte
    void element_op(A & a)
    {
        a.print();
    }
    
    //eine Deiner 20 abgeleiteten klassen
    struct C1 : A
    {
        virtual void print(){ std::cout << "I am C1" << std::endl; }
    };
    
    //eine andere Deiner 20 abgeleiteten Klassen
    struct C2 : A
    {
        virtual void print(){ std::cout << "I am C2" << std::endl; }
    };
    
    int main()
    {
        //Listen mit spzeifischen Typen
        std::list<C1> l1(10);
        std::list<C2> l2(25);
    
        //Benutzung
        list_loop(l1);
        list_loop(l2);
    }
    


  • Richtige objektorientierte Sprachen bieten für solcherlei Metaprogrammierung standardmäßig alles Notwendige an.
    Von jedem Objekt und von jeder Klasse (Klasse ist hierbei auch wieder ein Objekt) aus kann jederzeit der gesamte Klassenbaum eingesehen werden, ohne jede RTTI oder sonstwas für Frickelei.

    MFC bietet für CObjekt-Bäume sowas an, nennt sich CRuntimeClass und die hat zumindest

    CRuntimeClass* m_pNextClass;       // linked list of registered classes
    


  • Wutz schrieb:

    Richtige objektorientierte Sprachen bieten für solcherlei Metaprogrammierung standardmäßig alles Notwendige an.

    Jein. Sprachen, die die Einschränkung haben, dass alles "irgendwie objektorientiert" ablaufen muss und alles in eine Klassenhierarchie zwängen (und sich deshalb als rein objektorientiert bezeichnen), liefern häufig solche Klassenhierarchie-Zugriffe mit sich.

    Von jedem Objekt und von jeder Klasse (Klasse ist hierbei auch wieder ein Objekt) aus kann jederzeit der gesamte Klassenbaum eingesehen werden, ohne jede RTTI oder sonstwas für Frickelei.

    Die Möglichkeit, an ein entsprechendes Class-Objekt zu kommen (Reflection und was es da sonst noch alles gibt), ist RTTI. Statt eines Pointers auf eine vtable hat in Java, C# usw. jedes Objekt von Haus aus immer eine Referenz auf das Class-Objekt der Klasse.

    MFC bietet für CObjekt-Bäume sowas an, nennt sich CRuntimeClass und die hat zumindest

    CRuntimeClass* m_pNextClass;       // linked list of registered classes
    

    Hat aber alles mit dem eigentlichen Problem hier nichts zu tun, nämlich Referenzen/Pointer auf verschiedene abgeleitete Objekte derselben Basisklasse in einem gemeinsamen Container abzulegen.



  • pumuckl schrieb:

    Jein. Sprachen, die die Einschränkung haben, dass alles "irgendwie objektorientiert" ablaufen muss und alles in eine Klassenhierarchie zwängen (und sich deshalb als rein objektorientiert bezeichnen), liefern häufig solche Klassenhierarchie-Zugriffe mit sich.

    Quatsch.
    Richtige OOP-Sprachen haben per Definition eben keine Einschränkungen, wenn es um Klassenhierarchie-Services zur Laufzeit geht. Und es läuft auch nicht alles "irgendwie objektorientiert" ab, sondern "alles ist ein Objekt".
    Da braucht es dann auch keinen extern dazugelinkten RTTI-Krams, weil eben alles Notwendige standardgemäß immer mit dabei ist.



  • Wissend, dass ich mich auf Terrain begebe, auf dem (aus mir nicht wirklich verständlichen Gründen) die Emotionen hochschlagen: Der Begriff "objektorientierte Sprache" ist nicht besonders präzise, weil Objektorientierung in erster Linie keine Eigenschaft der Sprache ist. Ein Modell kann objektorientiert sein, eine Sprache eigentlich nicht - sie kann den Programmierer lediglich bei der Umsetzung objektorientierter Modelle unterstützen. So ist es durchaus möglich, in C objektorientierten Code zu schreiben, aber halt nicht besonders bequem. Es ist auch möglich, in Java Code zu schreiben, der nicht objektorientiert ist (aber halt nicht besonders bequem).

    Der Zugriff auf die Klassenhierarchie zur Laufzeit gehört allerdings klassisch nicht zum objektorientierten Programmierparadigma - sie verstößt gegen die Idee der Kapselung. Wenn ich mehr über ein Objekt wissen muss als ich in der Schnittstelle verlangt habe, ist meine Schnittstelle schlecht entworfen. dynamic_cast etc. sind das, was ich gern eine Konzession an die Realität nenne - in der Praxis braucht man halt manchmal ein Provisorium, wenn etwas bis gestern wieder laufen soll. Idealerweise verschafft man sich so Zeit, in der man es richtig lösen kann.

    Davon abgesehen ist es natürlich auch nicht sinnvoll, alle Probleme in ein vollständig objektorientiertes Schema pressen zu wollen.



  • Wutz schrieb:

    Richtige OOP-Sprachen haben per Definition

    Das ist das Problem: DieDefinition. Es gibt nämlich nicht eine Definition von Objektorientiert, sondern hunderte. Und die unterscheiden sich darin, was alles nötig ist, um etwas als objektorientiert bezeichnen zu dürfen. Und natürlich verlangen Fans von Java, C# etc. in ihren Definitionen, dass eine objektorientierte Sprache Services für Klassenhierarchien haben muss.
    Andere Definitionen setzen so tief an, dass man selbst in C objektorientiert programmieren kann, also ganz ohne Vererbung etc.

    Wutz schrieb:

    Und es läuft auch nicht alles "irgendwie objektorientiert" ab, sondern "alles ist ein Objekt".

    Schau dir mal den C++-Standard an. Dort wird so ziemlich alles als "Objekt" bezeichnet. Pointer, ints, doubles,... Da kommt also gleich die nächste Definitionsfrage - was ist ein Objekt? Da gibts mindestens so viele Definitionen wie zu "objektorientiert".

    seldon schrieb:

    Davon abgesehen ist es natürlich auch nicht sinnvoll, alle Probleme in ein vollständig objektorientiertes Schema pressen zu wollen.

    Ketzer 😉 Wer ein "echter" OO-Programmierer ist und mit "richtigen" objektorientierten Sprachen arbeitet, kann aus allem ein Objekt machen. 😉


Anmelden zum Antworten