Wie mit generischen Zeigern umgehen?



  • Ich möchte verschiedene Klassen in einer Liste unterbringen, damit ich sie in einer Schleife abarbeiten kann. Da kommen also wohl typenlose Zeiger in Frage. Schon bei den ersten Versuchen damit bleibe ich stecken. Trotz des Castings gelingt nicht der Zugriff über den typenlosen Zeiger:

    class Class1 {
    public:
    	int val;
    	void SetVal (int v) {val = v;}
    	void ShowVal () {printf ("\n Wert: %i \n", val);}
    };
    
    int main() {
    	Class1 Simple;
    	Simple.SetVal (123);
    	Simple.ShowVal (); // ok, zeigt 123 an
    
    	// nun mit typisiertem Zeiger
    	Class1 *PSimple = &Simple;
    	PSimple->ShowVal (); // auch ok
    
    	// schließlich mit generischem Zeiger
    	void *GenSimple;
    	GenSimple = (Class1*) &Simple;
    	GenSimple->ShowVal ();  // error: void is not a pointer-to-object type
    }
    

    Was mache ich falsch?



  • das wird so nicht sinnvill.
    es wird erst ok, wenn es auch einen grund gibt, die pbjekte in eine gemeinsame liste zu stopfen und in der schleife den gleichen funktionsaufruf zu machen. und dann haste sinnigerweise ne gemeinsame basisklasse, in der jene funktion virtual deklariert ist.



  • Was volkard damit sagen will ist, dass deine Klassen von einer gemeinsamen Basisklases erben sollen. Diese "kennt" dann alle Funktionen, die du in deiner Liste aufrufen willst. siehe auch Vererbung und Polymorphie.

    class basisKlasse {
        virtual void ShowVal() = 0; // Funktion deklarieren, alle Kindklassen müssen diese implementieren
    }
    
    class Class1 : public basisKlasse{
    public:
        int val;
        void SetVal (int v) {val = v;}
        virtual void ShowVal () {printf ("\n Wert: %i \n", val);}
    };
    
    int main() {
        Class1 Simple;
        Simple.SetVal (123);
    
        // mit basisklasse die die Funktion ShowVal() kennt
        basisKlasse *GenSimple;
        GenSimple = &Simple;    // kein Cast notwendig
        GenSimple->ShowVal ();  // basisKlasse kennt ShowVal(), Class1::ShowVal wird gerufen
    }
    


  • Um das Problem mal zu beantworten:
    Du kannst void-Zeiger nicht dereferenzieren, weil die Größe des Datenobjekts, auf das gezeigt wird, unbekannt ist. Deswegen bräuchtest du zuerst einen Cast. Also sowas:

    ((Class1 *)GenSimple)->ShowVal ();

    Aber das ist natürlich hässlich und wenn ich mir deinen Code so betrachte, sieht es schwer nach einer Mischung aus C und C++ aus (-> printf, void-Zeiger-Gecaste). Nimm dir die Tipps meiner Vorredner zu Herzen. 😉 (Aber auch hier bitte nicht printf verwenden. Das ist einfach C.)



  • Ja, die Richtung habe ich nun erkannt. Es geht wirklich darum, verschiedene Objekte in eine Liste zu packen, die zur Laufzeit aufgebaut wird und mit gemeinsamen Funktionsaufrufen angesprochen werden soll.

    Und was C angeht: In der Tat, ich bin dabei, mein C-Geschreibsel nach C++ umzubauen, und so einige Gewohnheiten brechen noch durch.

    Danke



  • moagnus schrieb:

    Du kannst void-Zeiger nicht dereferenzieren, weil die Größe des Datenobjekts, auf das gezeigt wird, unbekannt ist.

    Nicht nur die Grösse, sondern die gesamte interne Darstellung des Datentyps.

    erin schrieb:

    Und was C angeht: In der Tat, ich bin dabei, mein C-Geschreibsel nach C++ umzubauen, und so einige Gewohnheiten brechen noch durch.

    Ich würde dir raten, unbedingt ein C++-Buch anzuschaffen. Die prozeduralen Dinge wie Schleifen und Funktionen mögen in C und C++ noch einigermassen gleich sein, aber wenn es um Objektorientierung, Templates und die Standardbibliothek geht, bist du mit Neulernen besser beraten als mit Umlernen. Die Konzepte unterscheiden sich um Dimensionen.


Anmelden zum Antworten