Objekte unterscheiden: Funktion ist_ein(...) implementieren



  • Hallo,

    ich hätte für mein Projekt gerne folgende Funktionalität, die ich aus einem anderen Projekt kenne, aber nicht mehr genau weiss, wie sie realisiert wurde 🙄

    Ich hätte gerne in jeder Klasse eine öffentliche Funktion

    virtual bool ist_ein(const CKlassenBeschreiber&)
    

    die mir "wahr" liefert, wenn ein Objekt der Klasse entspricht.

    Nehmen wir an, ich hätte die Klassen "Fahrzeug", davon abgeleitet "Auto".
    Nun habe ich einen Zeiger auf ein Auto (wobei ich nicht weiss, dass es sich um ein Auto handelt), dann soll die Funktion ist_ein(AUTO) true liefern und der Aufruf ist_ein(FAHRZEUG) ebenfalls.

    In der Implementierung, die ich mal gesehen habe, hatte jede Klasse ein Objekt

    extern const CKlassenBeschreiber AUTO //bzw. FAHRZEUG
    

    Leider fehlt mir der entscheidende Ansatz.

    Kann mir jemand helfen? Seh ich vielleicht den Wald vor lauter Bäumen nicht oder ist es doch nicht so trivial? Was ist mit typeid etc.? Hilft mir ja nicht, wenn ich auch Basisklassen erkennen will oder?

    Vielen Dank.



  • Hallo

    dazu kannst du dynamic_cast<> benutzen.

    Fahrzeug *MeinFahrzeug;
    ...
    Auto *MeinAuto = dynamic_cast<Auto *>(MeinFahrzeug);
    if (MeinAuto)
    {
      // MeinnFahrzeug war vom Typ Auto
      }
    

    Dazu must du in deinem Compiler aber die RTTI aktivieren.

    Allerdings ist es besser, wenn du durch eine geeignete Basisklasse (mit virtuellen Methoden) nicht wissen must, von welchem Typ die Instanz letztendich ist.

    bis bald
    akari



  • Muß man für einen dynamic_cast wirklich RTTI aktivieren?



  • Hallo

    Überleg dir mal, was RTTI bedeutet und was den der dynamic_cast überprüfen soll.

    bis bald
    akari



  • OK, aber

    Auto* mercedes = new Auto();
    

    Dann funktioniert

    if(mercedes->ist_ein(FAHRZEUG))
    {...}
    

    aber nicht oder?

    D.h. ich kann keine Rückschlüsse auf die Basisklasse ziehen.



  • Hallo

    nein, so geht das in C++ nicht. Wie so etwas gemacht werden kann, hab ich dir doch schon geschrieben.

    bis bald
    akari



  • Hallo

    nein, so geht das in C++ nicht. Wie so etwas gemacht werden kann, hab ich dir doch schon geschrieben.

    bis bald
    akari

    Das ist nicht zufriedenstellend! Ich will doch nicht casten 🙂

    Also hier mein einfacher Vorschlag:

    class CKlassenBeschr
    {
    private:
    	const int fid;
    	static int sid;
    public:
    	CKlassenBeschr();
    
    	virtual ~CKlassenBeschr();
    
    	const int gib_id() const { return fid; };
    };
    
    const bool operator==(const CKlassenBeschr& akbl, const CKlassenBeschr& akbr);
    
    #include "klassenbeschr.h"
    
    int CKlassenBeschr::sid = 0;
    
    CKlassenBeschr::CKlassenBeschr():fid(sid)
    {
    	sid++;
    }
    
    CKlassenBeschr::~CKlassenBeschr()
    {
    }
    
     const bool operator==(const CKlassenBeschr& akbl, const CKlassenBeschr& akbr)
     { 
    	 return akbl.gib_id()==akbr.gib_id()?true:false; 
     };
    
    const CKlassenBeschr C_KLASSE;
    
    class CKlasse:public CKlasse2
    {
    private:	
    public:
    	CKlasse();
            const bool ist_ein(const CKlassenBeschr & akb) const { return (akb==C_KLASSE || CKlasse2::ist_ein(akb))?true:false; } 
    };
    


  • Ja, das ist auch eine Möglichkeit - nur solltest du die CKlassenBeschr eventuell etwas anpassen:
    * virtueller Destruktor ist unnötig (oder willst du etwas davno ableiten?)
    * ob Kopien nötig sind, weiß ich auf Anhieb nicht - eventuell könntest du Copy-Ctor und op= privat deklarieren
    * staische globale Objekte werden in zufälliger Reihenfolge initialisiert - also bekommst du vermutlich Probleme, wenn eins deiner Class-ID Objekte vor CKlassenBeschr::sid angelegt wird



  • Noch ein Tipp wegen den statischen sachen...
    Du kannst es auch so machen;

    class Klasse
    {
    public:
      static char dummy;
      const int gib_id() { return reinterpret_cast<int>(&dummy); }
    }
    

    Nimmt man die Adresse hat man zwei Vorteile:
    - Sie ist eindeutig
    - Sie ist auf jeden Fall initialisiert

    Bei Deiner Idee könnte man doch zum Beispiel sagen jeder "BasisTyp" bekommt eine Primzahl als Typ-Id. Jeder abgeleitete Typ hat die Typ_id: BasisTypId * die BasisPrimzahl. Damit könnte man ja sogar Mehrfachableitungen hinkriegen. Oder? (Nicht für riesen Projekte geeignet)



  • Danke Leute, prima Ideen 👍 !!!



  • Schon klar, dass RTTI Informationen zur Laufzeit bereitstellt

    Aber stehen in der vtable nicht eh die typids und die werden dann verglichen?

    Also möchte ich die Frage nochmal in den Raum stellen

    Muß man für einen dynamic_cast wirklich RTTI aktivieren?


Anmelden zum Antworten