Über Basisklassenzeiger Zugriff auf abgeleitete Klasse möglich?



  • Habe es jetzt doch selbst hinbekommen:

    static_cast<Vogel*>(t)->Fliegen();
    


  • volkard schrieb:

    void main()
    {
    	Tier* t = new Vogel();
    
    	t->Fliegen(); // error C2039: "Fliegen": Ist kein Element von "Tier"
    
            Vogel* v=static_cast<Vogel*>(t);//dafür kommst du aber in die Hölle
            v->Fliegen();
    
    	cin.get();
    }
    

    Hallo Volkard,

    danke für die Antwort.

    "Dafür kommst du aber in die Hölle".

    Sollte "Casting" denn möglichst immer vermieden werden? Das besagte Programmteil ist nicht Laufzeit kritisch. Es handelt sich um einen Menübefehl, der via "Cast" einem Setter() zugewiesen wird.



  • mireiner schrieb:

    Sollte "Casting" denn, falls irgend möglich, immer vermieden werden?

    Ja. Ist ein wenig wie goto.

    Aber dazu brauchste virtuelle Methoden und dynamic_cast und sowas ähnliches wie Objektorientierte Programmierung für Dummies | ISBN: 3826629841.

    mireiner schrieb:

    Das besagte Programmteil ist nicht Laufzeitkritisch. Es handelt sich um einen Menünefehl, der einem Setter() zugewiesen wird.

    Das besagte Programmteil ist nicht kritisch, weil das Programm nicht ein großes Programm mit 100 Klassen werden wird.



  • Ohne virtuelle Funktionen macht die Ableitung hier denke ich so oder so wenig Sinn. Für dynamic_cast kommst du aber auch in die Hölle, da führt wohl kein Weg dran vorbei.



  • Ich habe mich für Objekte, die über einen Basisklassenzeiger erzeugt werden entschieden, weil die später mit virtuellen Funktionen sehr einfach einheitlich aufgerufen werden können:

    t->Berechnen();
    t->Bewegen();
    t->Zeichnen();
    usw..
    

    Nur wird es dann schwierig, wenn Objekt Eigenschaften und Funktionen aufgerufen werden sollen, die nur einem einzigen Objekt gehören. Dafür virtuelle Funktionen auch bei allen anderen Objekten einzurichten, die diese Eigenschaften nicht haben, macht ja keinen Sinn. Für diesen Fall ist dann das "Casting" gedacht, um über den Basisklassenzeiger an die "speziellen" Funktionen zu gelangen.

    Im Grunde ist doch der Aufruf von abgeleiteten Klassen mit virtuellen Funktionen über einen Basiklassenzeiger ein nicht seltenes Design. Da muss es doch auch eine Lösung ohne "Casting" geben, um an Sonderfunktionen einzelner Objekte zu kommen. An dem Punkt habe ich ein Brett vorm Kopf. Weiß jemand vielleicht, wie das gehen könnte?



  • mireiner schrieb:

    Im Grunde ist doch der Aufruf von abgeleiteten Klassen mit virtuellen Funktionen über einen Basiklassenzeiger ein nicht seltenes Design. Da muss es doch auch eine Lösung ohne "Casting" geben, um an Sonderfunktionen einzelner Objekte zu kommen. Weiß jemand vielleicht, wie das gehen könnte?

    Ich denke, dafür ist dein gesamtes Design noch nicht ausgereift genug. Meist braucht man das nicht. Wenn du an einer Stelle, an der du nur über Basisklassenzeiger verfügst weißt, dass es bestimmte Ableitungen gibt, ist das Design schon irgendwie falsch.



  • mireiner schrieb:

    Im Grunde ist doch der Aufruf von abgeleiteten Klassen mit virtuellen Funktionen über einen Basiklassenzeiger ein nicht seltenes Design. Da muss es doch auch eine Lösung ohne "Casting" geben, um an Sonderfunktionen einzelner Objekte zu kommen. An dem Punkt habe ich ein Brett vorm Kopf. Weiß jemand vielleicht, wie das gehen könnte?

    Bei Dir fehlt doch aber eine überschriebene virtuelle Funktion?

    #include <iostream>
    
    using namespace std;
    
    class Tier
    {
    public:
      virtual void Bewegen() = 0;  // Tier ist abstrakt
      virtual ~Tier() = default;   // Tier ist Basisklasse
    };
    
    class Vogel : public Tier
    {
    public:
        void Bewegen() override
        {
            cout << "Vogel fliegt\n";
        }
    };
    
    int main()  // Rueckgabetyp von main() ist int
    {
        Tier* t = new Vogel();
        t->Bewegen();
        delete t;
        cin.get();
    }
    


  • Mechanics schrieb:

    Ich denke, dafür ist dein gesamtes Design noch nicht ausgereift genug. Meist braucht man das nicht. Wenn du an einer Stelle, an der du nur über Basisklassenzeiger verfügst weißt, dass es bestimmte Ableitungen gibt, ist das Design schon irgendwie falsch.

    So etwas hatte ich schon geahnt. Da bleibt mir wohl nur, die grundlegende Struktur noch einmal neu zu überdenken.

    Danke fur den Rat.



  • Wobei ich doch ergänzen muss, dass man ab und zu nicht sinnvoll ohne Casts auskommt. Braucht man am ehesten im GUI Code. Wenn dir das GUI Framework eine Möglichkeit bietet, an die Elemente (z.B. Menüpunkte) beliebige Daten anzuhängen, und du dann beim Ausführen ganz sicher weißt, was das ist, dann kann man schon einfach casten, da lohnen sich irgendwelche anderen Lösungen auch nicht. Das ist jetzt aber auch nicht unbedingt ein Fall, wo du etwas über Basisklassenzeiger verwaltest.



  • Mechanics schrieb:

    Wobei ich doch ergänzen muss, dass man ab und zu nicht sinnvoll ohne Casts auskommt. Braucht man am ehesten im GUI Code. Wenn dir das GUI Framework eine Möglichkeit bietet, an die Elemente (z.B. Menüpunkte) beliebige Daten anzuhängen, und du dann beim Ausführen ganz sicher weißt, was das ist, dann kann man schon einfach casten, da lohnen sich irgendwelche anderen Lösungen auch nicht. Das ist jetzt aber auch nicht unbedingt ein Fall, wo du etwas über Basisklassenzeiger verwaltest.

    Jo, das ist void* nach Data* casten. Oder char* nach Data*.

    Der static downcast fällt mir jetzt nur bei doppelt verketten Listenknoten ein.



  • volkard schrieb:

    Der static downcast fällt mir jetzt nur bei doppelt verketten Listenknoten ein.

    Hmm, warum? Steh grad auf dem Schlauch.



  • Mechanics schrieb:

    volkard schrieb:

    Der static downcast fällt mir jetzt nur bei doppelt verketten Listenknoten ein.

    Hmm, warum? Steh grad auf dem Schlauch.

    Weil ich die als doppelt verketteten niemals leeren Ring implementiere, dadurch gibts kein if mehr im Code.

    template<typename Data>
    class List{
        struct NodeBase{
            NodeBase* prev;
            NodeBase* pred;
        };
        struct Node:public NodeBase{
            Data data;
        };
        NodeBase anchor;
    public:
        List(){
            anchor->prev=&anchor;
            anchor->pred=anchor;
        }
        bool isEmpty(){
            return anchor->prev==anchor;
        }
        Data& peekFront(){
            return static_downcast<Node*>(anchor.pred)->data;
        }
        Data& peekBack(){
            return static_downcast<Node*>(anchor.prev)->data;
        }
        void pushFront(Data const& data){
            Node* n=new Node(data);
            n->prev=anchor;
            n->pred=anchor->pred;
            n->prev->pred=n;
            n->pred->prev=n;
        }
    


  • In CRTP sind sie auch nicht toxisch


  • Mod

    volkard schrieb:

    ...
    

    prev und pred ?



  • camper schrieb:

    volkard schrieb:

    ...
    

    prev und pred ?

    Ähm, einer der beiden Bezeichner lügt aber gewaltig.
    prev/next oder pred/succ, aber prev/pred ist Vollquatsch.



  • Grad auf nem Trip oder wie 😕


Anmelden zum Antworten