*superklasse in *abgeleitete_klasse casten



  • Hallo!

    Ich habe ein Array aus Pointern auf eine Basisklasse um dort Elemente unterschiedlicher jedweils von dieser Basisklasse abgeleiteter Klassen unter zu bringen.
    Jetzt will ich die da aber auch wieder auslesen. Wie mache ich das? Wie mache ich aus dem Datentypen *Superklasse eine *Unterklasse?

    Grüße, pktm



  • Du könntest das brutal mit dynamic_cast abfragen, aber ob das guter Stil ist...



  • Das ist normalerweise gar nicht nötig, da das bereits die Polymorpie erledigt. Kleines Beispiel:

    class Base
    {
        public:
            virtual ~Base() {} // virtuellen Destruktor nicht vergessen, damit auch das komplette Objekt wieder gelöscht wird
            virtual void print() { std::cout << "Base" << std::endl; }
    };
    class Derived : public Base
    {
        public:
            virtual void print() { std::cout << "Derived" << std::endl; }
    };
    int main()
    {
        Base b;
        Derived d;
    
        Base* ptr = &b;
        ptr->print() // gibt "Base" aus
        ptr = &d;
        ptr->print() // gibt "Derived" aus
    }
    


  • Naja, in dem Moment wo ich typisierte Methoden verwende die meckern, wenn ich ihnen eine Superklasse andrehen möchte ist das schon relevant.

    Hier mal noch etwas Code von mir (die Klassen sind leider zu umfangreich zum Posten):

    CAccount* giro_konten[255]; // das Array mit der Basisklasse
    CGiro acc(parameter hier);
    giro_konten[i] = &acc;
    

    Wenn ich CGiro* x = (CGiro*) giro_konten[i]; versuche klappts nicht, sondern wirft den Fehler "C2635: Konvertierung von 'CAccount*' in 'CGiro*' nicht möglich; implizite Konvertierung einer virtuellen Basisklasse" 😞



  • Die Frage ist, ob dieser Downcast WIRKLICH notwendig ist.



  • this->that schrieb:

    Die Frage ist, ob dieser Downcast WIRKLICH notwendig ist.

    Na, klappt es denn, wenn ich so einer Methode hier einen CAccount-Pointer zum Fraß vorwerfe?

    /**
     * <p>Compares two objects. Returns &quot;TRUE&quot;, if the objects' memory addresses are equal, else returns &quot;FALSE&quot;.</p>
     * 
     * 
     * @param account Compares two objects. Returns &quot;TRUE&quot;, if the objects' memory addresses are equal, else returns &quot;FALSE&quot;.
     * @return 
     */
    bool CSavings::equal(CSavings account) {
    	// your code here
    }
    

    Grüße, pktm



  • Nein, natürlich nicht. Wieso spendierst du CAccount nicht einfach eine pure virtual Methode equal?



  • this->that schrieb:

    Nein, natürlich nicht. Wieso spendierst du CAccount nicht einfach eine pure virtual Methode equal?

    Weil ich dann den Fehler C2259 (Instanz von abstrakter Klasse kann nicht erstellt werden) erhalte. Da die Klasse abstrakt ist wird sie auch nie eine Instanz von sich zum prüfen erhalten.
    Oder muss ich das anders machen als so wie im Kode?

    bool virtual equal(CAccount account) = 0;
    

    Grüße, pktm



  • Dein Parameter ist falsch, darum kommt der Fehler.

    Du mußt eine Referenz (oder einen Zeiger) verwenden:

    bool virtual equal(const CAccount &account) = 0;
    
    // bool virtual equal(const CAccount *account) = 0;
    

    Und dann entsprechend bei allen abgeleiteten Klassen überladen.



  • pktm schrieb:

    ...

    Könnte es sein das du von Java oder C# kommst?

    Wie schon Th69 angedeutet hat muss es sich hier um Referenzen oder Zeiger handeln. Darüber hinaus solltest du dich aber grundlegend mit der Thematik (Value contra Referenz contra Zeiger) auseinandersetzen - und zwar nicht nur für diesen Fall.

    1. Ist die Übergabe eines nicht-integralen Datentyps per Kopie (Copy-by-Value) meist nicht sinnvoll.
    2. Polymorphie funktioniert nur mittels Refenzen und Zeigern.

    cu André



  • asc schrieb:

    Könnte es sein das du von Java oder C# kommst?

    Schlimmer, aus der Perl-Ecke 😃

    Werde mir die Sachen mal anschauen.

    Grüße, pktm



  • Ok, kann man denn nciht vielleicht doch irgendwie mit Gewalt erzwingen, dass diese Konvertierung von Statten geht?

    Grüße, pktm



  • pktm schrieb:

    Ok, kann man denn nciht vielleicht doch irgendwie mit Gewalt erzwingen, dass diese Konvertierung von Statten geht?

    Mit anderen Worten du nimmst ein Brecheisen und dein Sparschwein zu schlachten?

    class Base
    {
        virtual bool Equal(const Base& object);
    }
    

    Soll Wertüberprüfung oder Prüfung auf Objektidentität durchgeführt werden? Nehme mal ersteres an... Ggf. solltest du dir zudem auch mal RTTI anschauen (type_id).

    cu André



  • Hm... so ganz habe ich das jetzt nicht verstanden.

    Diese equal- und equalvalue-Methoden habe ich. Erstere prüft, ob es sich um das selbe Objekt handelt (identische Adresse), die zweite prüft die Werte auf Gleichheit.

    Und, ja so ein Brecheisen gegen ein Sparschwein hats schon in sich ^^
    Aber wahrscheinlich ist es wirklich nicht möglich.

    Mittlerweile habe ich auch andere Wege gefunden mein Ziel zu erreichen, aber das ist alles etwas umständlicher, bzw. der Weg ist anders.

    Grüße, pktm



  • pktm schrieb:

    Und, ja so ein Brecheisen gegen ein Sparschwein hats schon in sich ^^
    Aber wahrscheinlich ist es wirklich nicht möglich.

    Ich schätze schon das es möglich ist, aber wie ich schon in anderen Threads erwähnt habe ist meine Glaskugel zerbrochen, und ich kann so schlecht raten...

    pktm schrieb:

    Mittlerweile habe ich auch andere Wege gefunden mein Ziel zu erreichen, aber das ist alles etwas umständlicher, bzw. der Weg ist anders.

    Und vermutlich würde es mit etwas mehr C++ Verständnis auch anders besser zu lösen sein. Ich habe dir einfach mal ein Testprogramm fertiggestellt (nicht auf 100%ige Korrektheit überprüft, so aber unter VC++2005 lauffähig). Da ich nicht weiß wie genau ihr equal definiert habe ich mal 2 Varianten gemacht, eine in der der Typ 100% stimmen muss, und Wertgleichheit besteht, und eine wo auch unterklassen mit einbezogen werden.

    #include <iostream>
    #include <typeinfo>
    
    class Base
    {
    	public:
    		// Prüfung auf Wertgleichheit identischer Klassen
    		bool equal(Base const & object)
    		{
    			if(typeid(*this) == typeid(object))
    				return partEqual(object);
    			return false;
    		}
    		// Prüfung auf Wertgleichheit, wobei Unterklassen für die Gleichheit mitzählen
    		virtual bool partEqual(Base const & object) = 0;
    
    		virtual ~Base() {};
    };
    
    class A : public Base
    {
    	private:
    		int a;
    	public:
    		A(int a)
    		:	a(a)
    		{}
    
    		bool partEqual(Base const & object)
    		{
    			A const * obj = dynamic_cast<A const *>(&object);
    			if(obj)
    				return this->a == obj->a;
    			return false;
    		}
    };
    
    class B : public Base
    {
    	private:
    		int a;
    	public:
    		B(int a)
    		:	a(a)
    		{}
    
    		bool partEqual(Base const & object)
    		{
    			B const * obj = dynamic_cast<B const *>(&object);
    			if(obj)
    				return this->a == obj->a;
    			return false;
    		}
    };
    
    class C : public B
    {
    	private:
    		int b;
    	public:
    		C(int a, int b)
    		:	B(a),
    			b(b)
    		{}
    
    		bool partEqual(Base const & object)
    		{
    			C const * obj = dynamic_cast<C const *>(&object);
    			if(obj)
    			{
    				if(this->b == obj->b)
    				return B::partEqual(object);
    			}
    			return false;
    		}
    };
    
    int main()
    {
    	A a(1);
    	B b1(1);
    	B b2(1);
    	B b3(2);
    	C c(1, 2);
    
    	std::cout << "A a(1) equal B b1(1) : " << (a.equal(b1) ? "true" : "false") << std::endl; // false
    	std::cout << "B b1(1) equal B b2(1) : " << (b1.equal(b2) ? "true" : "false") << std::endl; // true
    	std::cout << "B b1(1) equal B b3(2) : " << (b1.equal(b3) ? "true" : "false") << std::endl; // false
    	std::cout << "B b1(1) equal C c(1, 2) : " << (b1.equal(c) ? "true" : "false") << std::endl; // false
    	std::cout << "B b1(1) partEqual C c(1, 2) : " << (b1.partEqual(c) ? "true" : "false") << std::endl; // true
    }
    

    cu André


Log in to reply