Per typeid auf Vererbung testen



  • Hallo,

    Kann man eigentlich in C++ per typeid testen, ob ein uebergebener Zeiger auf ein Objekt einer Basisklasse oder ein Objekt einer abgeleiteten Klasse zeigt?

    Ich wollte das mit folgendem Code machen, nur leider unterscheidet der Code nicht zwischen den Typen Basisklasse und Abgeleiteter Klasse sondern gibt jedesmal das Ergebnis fuer gleich mit "Base" aus. Ich denke das liegt daran, dass der uebergebene Zeiger in der "isDerived()" auf den Typ "Basis" zeigt (oder implizit konvertiert wird). Somit scheint er innerhalb der Funktion nicht keine Information mehr ueber seinen Ursprung zu haben?! Ist es irgendwie dennoch moeglich festzustellen ob, das dahinterliegende Objekt vom Typ einer abgeleiteten Klasse ist?

    Fragen:
    - Ist das oben beschriebene und unten ge-codete ueberhaupt moeglich?
    - ..und wenn ja - wo liegt mein Fehler?

    #include <iostream>
    #include <typeinfo>
    
    class Base
    {};
    
    class Derived : public Base
    {};
    
    /*
      typeid-wrapper (angelehnt an den Code von Alexandrescu / Modern C++ Design
    //*/
    class Typeinfo
    {
    private:
      const std::type_info* pInfo_;
    
    public:
      Typeinfo();
      Typeinfo(const std::type_info&);
      Typeinfo(const Typeinfo&);
      Typeinfo& operator=(const Typeinfo&);
      bool operator==(const Typeinfo&) const;
    };
    
    Typeinfo::Typeinfo()
    {}
    
    Typeinfo::Typeinfo(const std::type_info& t_i)
    {
      pInfo_ = &t_i;
    }
    
    Typeinfo::Typeinfo(const Typeinfo& ti)
    {
      pInfo_ = ti.pInfo_;
    }
    
    Typeinfo& Typeinfo::operator=(const Typeinfo& ti){
      if(&ti == this) return *this;
      this->pInfo_ = ti.pInfo_;
      return *this;
    }
    
    bool Typeinfo::operator==(const Typeinfo& rhs) const
    {  
      return pInfo_ == rhs.pInfo_; // XXX - ist dieser Vergleich hier richtig?
    }
    
    // zur Demonstration eine globale Variable..
    Base base;
    
    /*
      Die Idee ist, ein Zeiger wird nur uebergeben wenn er entweder von Base 
      oder Derived ist, sonst wuerde der Code nicht kompilieren. 
    
      Der uebergebene Zeiger soll dann verglichen werden ob er vom Basistyp ist
      ist dies nicht der Fall, ist er zwangslaeufig abgeleitet
    
      (Ist diese Schlussfolgerung ueberhaupt moeglich oder ist da ein Denkfehler 
      drin?)
    //*/
    void isDerived(Base* pObj)
    {
      Typeinfo info = typeid(base);
      if(info == typeid(*pObj)){
        std::cout << "zeigt auf Base object";
      }else{
        std::cout << "zeigt auf Derived object";
      }
      std::cout << std::endl;
    }
    
    int main()
    {
      using namespace std;
    
      // init
      cout << "init.." << endl;
      Base b;
      Derived d;
    
      cout << "check \'b\':\n";
      isDerived(&b);
      cout << endl;
    
      cout << "check \'d\':\n";
      isDerived(&d);
      cout << endl;
    
      cout << "READY.\n";
      return 0;
    }
    

    🙂



  • Die Klassen sind bei dir gar nicht polymorph (sie besitzen keine virtuellen Funktionen), deshalb kann typeid nicht gut damit umgehen.

    typeid ist generell unschön - man sollte es so wenig wie möglich verwenden. Für Debugging-Zwecke kann es praktisch sein, aber als Universallösung ist es nicht zu empfehlen.

    Mach es doch mit virtuellen Methoden, sodass je nach Klasse automatisch die richtige Methode aufgerufen wird. Aber für Polymorphie solltest du besser mit Zeigern oder Referenzen arbeiten.



  • Ok, danke, ich habe dasselbe mit virtuellen Funktionen in den Klassen versucht und es hat geklappt.

    Bei dem Problem ging es mir eher darum ob es eine Moeglichkeit gibt, evtl mit einem Wrapper (hab da eine Loesung gelesen) zu checken ob man einen downcast durchfuehren kann oder nicht. Sofern also virtual deklarierte Functionen in dem Code sind, wuerde dieser Ansatz funktionieren. Nja, schade dass es nur funktioniert wenn virtuelle Funktionen in den Klassen sind und nicht generell.

    Danke fuer die Antwort!



  • Um einen Downcast durchzuführen, bietet C++ ja den Operator dynamic_cast an. Wenn der Cast nicht funktioniert hat, wird bei Zeigern der Nullzeiger zurückgegeben und bei Referenzen eine Exception vom Typ std::bad_cast geworfen.

    Aber dynamic_cast ist auch nicht der Weisheit letzter Schluss; wieso willst du unbedingt einen Downcast durchführen? Grundsätzlich ist mit virtuellen Funktionen das Meiste zu lösen - je nach Klasse wird die richtige Funktion aufgerufen.


Anmelden zum Antworten