Zeigerzuweisung mit unterschiedlichen Zeigertypen



  • Hallo!
    Ich habe folgendes Codesegment:

    switch (m_ProcessorType)
        {
        case COP8CBE9:
            cCOP8CBE9* Flash = new cCOP8CBE9(this);
            break;
        }
    
        Error = Flash->ReadFlash(_AddressHighByte, _AddressLowByte);
        delete Flash;
    

    Hier beschwert sich der Compiler, dass Flash nicht deklariert sei. Klar, der
    Pointer liegt im Switch-Block, und ist somit ausserhalb nicht gültig.
    Meine Idee war, Flash zu einer Membervariablen der Klasse zu machen.
    Allerdings kann Flash in der weiteren Entwicklung des Programms von
    verschiedenen Typen sein, also nicht nur cCOP8CBE9*.
    Ich könnte die Zugriffe in die Switch-Anweisung mit aufnehmen, dann müsste ich
    aber diese Zeilen in jedem case wiederholen.
    Gibt es eine andere Möglichkeit?



  • C++ hat den Weg der Typsicherheit eingeschlagen. Das heisst, eine Variable kann nicht mehrere Typen haben, sondern nur den, mit dem sie deklariert wurde.

    Falls COP8CBE9 eine Klasse ist, könntest du diesen und die anderen Typen beispielsweise mit einer Basisklasse kompatibel machen, indem du Laufzeitpolymorphie nutzt. Durch virtuelle Funktionen wäre dafür gesorgt, dass je nach Typ, auf den der Zeiger zeigt, die entsprechende Methode aufgerufen wird.

    Ansonsten gäbe es nur noch die hässliche Möglichkeit des void -Zeigers. void* ist aber eher C und auch nicht typsicher, zudem muss er jedes Mal explizit dereferenziert werden, viel ist damit also nicht gewonnen. Vielmehr handelt man sich so hässliche Fallunterscheidungen, Frickelcode und Fehleranfälligkeit ein.



  • Das Problem mit der Basisklasse ist, dass es sich um eine Klasse handelt, die
    verschiedene Prozessortypen programmieren kann. Und je nach Typ unterscheiden
    sich diese Funktionen. Die meisten hätte ich in der Basisklasse nicht zur
    Verfügung.
    Vielleicht fahr ich mit dem Kopieren der beiden Zeilen am besten.



  • Das versteh ich jetzt nicht ganz...

    Kannst du denn nicht die Basisklasse so einrichten, dass sie und die abgeleiteten Klassen eine ähnliche Schnittstelle besitzen?



  • Naja, die Schnittstelle dürfte für alle Prozessoren gleich sein.
    Ich hab als Argumente ein Highbyte und ein Lowbyte für die Adresse,
    und einen vector<unsigned> für die Datenbytes. Momentan hab ich halt
    nur den COP8 implementiert, weil dieser in dem Gerät verbaut ist, das
    ich programmieren will. Der COP8 z. B. beschreibt nicht nur einzelne
    Bytes, sondern ganze Pages. Also dürfte sich nur der Funktionsrumpf
    ändern, ausser wenn mit mehr als 2 Bytes adressiert werden muss.
    Ich hab nicht so viel Erfahrung mit Polymorphie. Aber ich könnte doch
    auch eine abstrakte Basisklasse entwerfen, wo ich die READ-, Write-, und
    Erase-Funktion überschreiben muss. Zusätzliche Funktionen werden nicht
    hinzukommen. Kann ich denn überhaupt einen Objektzeiger der abgeleiteten
    Klasse übergeben, obwohl ein Objektzeiger auf die Basisklasse erwartet
    wird? In der abgeleiteten Klasse werden nicht mehr Funktionen vorhanden
    sein, wie in der Basisklasse. Sie werden die gleiche Signatur haben.



  • mase schrieb:

    Kann ich denn überhaupt einen Objektzeiger der abgeleiteten
    Klasse übergeben, obwohl ein Objektzeiger auf die Basisklasse erwartet
    wird?

    Ja, das ist eben der Vorzug der Polymorphie. Wenn virtuelle Funktionen in Basis- und abgeleiteter Klasse vorhanden sind, wird je nach Objekttyp, auf den der Zeiger zeigt, automatisch die richtige Funktion ausgewählt - auch wenn der Zeiger vom Typ "Zeiger auf Basisklasse" ist.

    mase schrieb:

    In der abgeleiteten Klasse werden nicht mehr Funktionen vorhanden
    sein, wie in der Basisklasse. Sie werden die gleiche Signatur haben.

    Dann würde ich es erst recht mit Polymorphie machen.

    Zur Verdeutlichung:

    class Base
    {
    	public:
    		virtual void Func() {std::cout << "Base." << std::endl;}
    };
    
    class Derived : public Base
    {
    	public:
    		virtual void Func() {std::cout << "Derived." << std::endl;}
    };
    
    void Output(Base* ptr)	// es wird ein Basisklassenzeiger erwartet, es können aber auch
    {						 // Zeiger auf abgeleitete Klassen übergeben werden.
    	ptr->Func();	// ruft je nach Objekt (*ptr) die richtige Funktion auf.
    }
    
    int main()
    {
    	Base b;
    	Derived d;
    	Base* pd = new Derived;
    
    	Output(&b);	// Base* zeigt auf Base.		   Ausgabe: Base.
    	Output(&d);	// Derived* zeigt auf Derived.	 Ausgabe: Derived.
    	Output(pd);	// Base* zeigt auf Derived.		Ausgabe: Derived.
    
        delete pd;
    }
    

    Was hier mit Zeigern geht, kann übrigens auch mit Referenzen gemacht werden.

    P.S. Das Forum besitzt eine automatische Zeilenumbruchsfunktion, so wäre dein Text ein bisschen flüssiger zu lesen... 😉



  • Danke, hat funktioniert!
    Ich habe eine abstrakte Basisklasse entworfen. Da hat sogar nur eine
    Headerdatei gereicht. Von der kann ich dann meine einzelnen Prozessorklassen
    ableiten.


Log in to reply