Wunderliches Problem



  • Hallo,

    ich habe eine Klasse:

    class MAPCLASS
    {

    MAPCLASS::MAPCLASS
    {
    IDrenderer = SDL_AddTimer(100, renderer, NULL);
    }

    Uint32 renderer(Uint32 interval, void *param)
    {
    ...
    }

    }
    Hier bekomme ich den Fehler:
    [C++ Fehler] MAPCLASS.h(42): E2342 Keine Übereinstimmung des Typs beim Parameter 'callback' ('unsigned int (*)(unsigned int,void *)' erwartet, 'void' erhalten)

    Ich verstehe nicht weshalb, aber ich habe dieses Problem nicht, wenn ich den Timer ausserhalb meiner Klasse deklariere und starte.



  • Den 'void' erhalten Teil verstehe ich nicht. Der Rest ist klar: ne nicht-statische Memberfunktion ist halt nicht das selbe wie ne freie Funktion.
    z.B. hat so ne nicht-statische Memberfunktion nen versteckten "this" Parameter.

    In deinem Fall aber einfach zu lösen, da die API ja netterweise nen void* in der Signatur hat wo man eigenes Zeugs durchschleifen kann. z.B. deinen "this" Zeiger den du brauchst um dann die nicht-statische Memberfunktion aufrufen zu können.



  • Vielen Dank für die Antwort. Ich denke ich habe da ein paar Lücken in den Grundlagen, denn auf diese Lösung wäre ich so schnell nicht gekommen.

    Danke 🙂



  • Ich bekomme es leider nicht hin. Was mir fehlt ist das Hintergrundwissen, um deinen Rat um zusetzten.

    Sollte es auf die schnelle möglich sein und du kurz die Zeit dafür haben, könntest du mir das kurz pseudomässig zusammenbauen anhand des Codes den ich oben gezeigt habe.

    Wie "baue" ich diesen this-Pointer und "schleife" ihn korrekt dadurch, so wie spreche ich die Funktion damit dann an?

    Ich habe die Hoffnung, die Lücken die ich habe, teilweise auf diese Weise schließen zu können.



  • class MAPCLASS
    {
      MAPCLASS::MAPCLASS
      {
        IDrenderer = SDL_AddTimer(100, renderer, this);
      }
    
      static Uint32 renderer(Uint32 interval, void *param)
      {
         MAPCLASS *pMap = static_cast<MAPCLASS *>(param);
    
         // ...
      }
    }
    

    PS: Das "CLASS" solltest du aus dem Namen streichen - und nur Großbuchstaben sind auch keine gute Code-Konvention (also einfach "Map" o.ä.)



  • mein Gott, so etwas habe ich noch nie gesehen:

    static_cast<MAPCLASS *>(param);

    in jedem Fall, vielen Dank. Ich werde mich jetzt erst mal damit befassen 🙂



  • Und nur weil's vielleicht nicht klar ist, wie man dann mit ner normalen (nicht-statischen) Memberfunktion arbeiten kann:

    class Map
    {
      Map::Map
      {
         IDrenderer = SDL_AddTimer(100, &Map::renderer_static, this);
      }
    
      static Uint32 renderer_static(Uint32 interval, void *param)
      {
         Map* instance = static_cast<Map*>(param);
         return instance->renderer(interval);
      }
    
      Uint32 renderer(Uint32 interval)
      {
         // ...
      }
    
    }
    


  • als ob du Gedanken lesen kannst:) Vielen Dank! In der Tat ist mir da hinten und vorne nichts klar, aber das liegt daran, das ich mich offensichtlich nicht ausreichend mit der Materie auskenne.

    Ich versuche zu sehen ob ich hiermit schon weiter komme, so oder so werde ich damit herum experimentieren, vllt verstehe ich es auf diese Weise.

    Vielen Dank in jedem Fall, Hustbaer!



  • Nachtrag:

    Fürs erste nenne ich dich schlicht "Großer Zauberer" oder wahlweise "Großer Meister" 😛

    Et funzt. Ich weiss nicht so recht, was an diesem statischem Kram so wichtig ist. Wann macht man eine Funktion statisch?

    Ich werde mir jetzt Tuts zu dem Thema geben.

    Du hast mir echt geholfen, vielen Dank 🙂



  • Hodor schrieb:

    Et funzt. Ich weiss nicht so recht, was an diesem statischem Kram so wichtig ist. Wann macht man eine Funktion statisch?

    Uff. Also ich versuchs mal.

    Wenn du ne Klasse schreibst... und in dieser Klasse ne normale (nicht-statische) Memberfunktion... dann hast du in dieser Memberfunktion Zugriff auf das Objekt. Also auf alle Membervariablen.
    Beispiel:

    class Foo
    {
    public:
        Foo()
        {
            member = 0;
        }
    
        void Bar()
        {
            member++;
            std::cout << member << "\n";
        }
    
    private:
        int member;
    };
    

    "Bar" ist hier nicht-statisch, also kannst du in "Bar" auf "member" zugreifen.

    Du kannst jetzt aber beliebig viele "Foo" Objekte erstellen, d.h. irgendwoher muss "Bar" wissen um welches Objekt es geht.
    Also bei ...

    Foo x;
        Foo y;
        x.Bar();
    

    ... muss "Bar" wissen dass es um "x" geht und nicht um "y".

    "Bar" hat aber keine Parameter, also muss es da noch 'was geben. Und dieses noch was ist "this". Das ist quasi ein versteckter Parameter der auf "das Objekt um das es geht" zeigt. Das sieht man, wenn man "Bar" z.B. so schreibt:

    void Bar()
        {
            this->member++;
            std::cout << this->member << "\n";
        }
    

    Macht genau das selbe wie vorhin, nur dass jetzt "sichtbar" ist dass es hier diesen versteckten "this" Parameter gibt.

    Und bei einem Aufruf ala "x.Foo()" oder "pointer->Foo()" wird die Adresse von "x" bzw. der Wert von "pointer" automatisch als Wert für diesen versteckten Parameter verwendet und mit an "Bar" übergeben. Was auch erklärt dass man solche Funktionen "nicht ohne Objekt" aufrufen kann -- irgendwas muss ja für "this" übergeben werden, und wenn kein Objekt da ist... geht das halt nicht. ("this" darf nie NULL sein!)

    Ich hoffe das ist soweit mal verständlich.

    Und eine statische Funktion zeichnet sich nun einfach dadurch aus dass sie eben gerade keinen solchen versteckten "this" Parameter hat. Daraus folgt nun auch dass du in einer statischen Funktion natürlich auch keinen Zugriff auf irgendwelche Member des Objekts hast -- denn es gibt ja kein "this" das bestimmen würde um welches Objekt es geht.

    In dieser Hinsicht ist eine statische Funktion also wie eine sog. "freie" Funktion (eine Funktion die zu keiner Klasse gehört).

    Jetzt noch zu der Frage wieso du bei SDL_AddTimer keine nicht-statische Memberfunktion verwenden kannst. Die Antwort ist ganz einfach: SDL_AddTimer erwartet einen Zeiger auf eine "freie" Funktion. Also nix mit "this" und daher nix mit nicht-statischen Memberfunktionen. Statische Memberfunktionen gehen allerdings, da diese bei allem was hier relevant ist mit freien Funktionen kompatibel sind.

    Und jetzt sollte hoffentlich auch klar sein wie man drumrum arbeitet.
    SDL_AddTimer hat ja diesen "param" Parameter wo man bei SDL_AddTimer nen Wert reingeben kann, und den selben Wert beim Aufruf der Callback-Funktion wieder zurück bekommt. Und hier schleusen wir unser "this" durch.
    D.h. wenn "renderer_static" aufgerufen wird zeigt "param" auf das "Map" Objekt. Da "param" ein void* ist, muss man diesen erstmal wieder in einen Map* verwandeln, das macht der static_cast (BTW: nicht verwirren lassen - das static in static_cast hat *nichts* mit dem static bei der Memberfunktion zu tun, das ist bloss zufällig das selbe Wort!).
    Und mit dem dieserart "rückgewonnenen" Zeiger auf das Objekt können wir dann die nicht-statische "renderer" Funktion aufrufen.



  • Danke


Anmelden zum Antworten