Wenn ich virtuelle Methode aufrufe kracht es



  • // pThis ist ein statischer Zeiger auf den this Zeiger
    // damit ich auch auf non-static Methoden meiner Klasse
    // zugreifen kann.

    Hääää?! Sorry, ich glaube, du hast einige Konzepte nicht verstanden.
    Wie auch immer, kannst ja mal mit dem Debugger durchgehen, das hilft dir wahrscheinlich am ehesten.



  • Optimizer schrieb:

    // pThis ist ein statischer Zeiger auf den this Zeiger
    // damit ich auch auf non-static Methoden meiner Klasse
    // zugreifen kann.

    Hääää?! Sorry, ich glaube, du hast einige Konzepte nicht verstanden.
    Wie auch immer, kannst ja mal mit dem Debugger durchgehen, das hilft dir wahrscheinlich am ehesten.

    Also 1. es liegt an der virtuellen Methode denn wenn ich das virtual weglasse, läuft alles wie geschmiert. Das Objekt ist auch initialisiert.

    2. muss ich den pThis auf den this zeiger setzen, damit ich in der statischen Methode auf die Klassemethoden zugreifen kann. ich habe bereits debugged und festgestellt das es kracht wenn ich die mit virtual deklarierte Methode aufrufen will.

    Es hat schon alles seine Richtigkeit die static Methode wird nicht!!! so aufgerufen:

    Klasse::Methode();
    


  • Moin,

    zwar nicht zum Thema, aber warum dann static?

    mfg
    v R



  • 2. muss ich den pThis auf den this zeiger setzen, damit ich in der statischen Methode auf die Klassemethoden zugreifen kann. ich habe bereits debugged und festgestellt das es kracht wenn ich die mit virtual deklarierte Methode aufrufen will.

    LOL. Also eine Klasse kann millionenfach instanziert werden. jedes Objekt hat eine Adresse, die dann beim Aufruf jeweils der aktuelle this-Zeiger ist. "DEN" this-Zeiger gibt es also nicht. Er Variiert von Objekt zu objekt, auf dem die Methode aufgerufen wird.

    -- helium, der vergessen hat sich einzuloggen und es ert gemerkt hat, nachdem er den Text geschreiben hat und nun keine Lust einen riesigen Aufwand zu betreiben, um das richtigzubiegen.



  • virtuell Realisticer schrieb:

    Moin,

    zwar nicht zum Thema, aber warum dann static?

    mfg
    v R

    Die Methode muss static sein da es sich bei der Klasse um eine "Window"- Klasse handelt, also ähnlich wie bei dem C++ Builder eine TForm. Zum erzeugen eines solchen Fensters benötigt man eine Funktion welche die Nachrichten von Windows empfängt. Da ich diese Methode gern innerhalb der Klasse hätte ich sie so allerdings nicht mehr in den benötigten yp casten kann muss sie statisch sein.



  • Erklär doch mal, wo und wie pThis initialisiert wird.



  • Hallo,

    wird vielleicht der Wert von pThis irgendwie geaendert (durch z. B. eine Bereichs-
    ueberschreitung oder sowas)? Gibt es Stellen in deiner Funktion (z. B. Funktions-
    anfang), wo pThis noch gueltig ist und dann spaeter vielleicht nicht mehr?

    mfg
    v R



  • I_Need_Help schrieb:

    2. muss ich den pThis auf den this zeiger setzen, damit ich in der statischen Methode auf die Klassemethoden zugreifen kann.

    Ja, musst du. Wie aber helium bereits sagte, können sich hinter this unzählige verschiedene Instanzen verbergen.
    Zeig doch einfach mal die Codezeilen, wo pThis geändert wird.



  • Hi,

    Das ganze macht für mich persönlich nur Sinn bei einer Singleton - Klasse.
    Ansonsten würde das eintreten was die anderen bereits erwähnt haben.

    MfG



  • groovemaster schrieb:

    I_Need_Help schrieb:

    2. muss ich den pThis auf den this zeiger setzen, damit ich in der statischen Methode auf die Klassemethoden zugreifen kann.

    Ja, musst du. Wie aber helium bereits sagte, können sich hinter this unzählige verschiedene Instanzen verbergen.
    Zeig doch einfach mal die Codezeilen, wo pThis geändert wird.

    pThis wird nur einmal geändert, bei der Message WM_CREATE. Bei dem WinApi Aufruf CreateWindow:

    hWnd = CreateWindowEx ( 0, szClassName, NULL, WS_CHILD, x, y, width, height, hParent, NULL, hInstance, (void*) this ); 
    //Der letzte Parameter ist der this Zeiger
    

    Dann wird von Windows an die von mir angegeben Funktion die Nachricht WM_CREATE gesendet dort kann ich dann so this an pThis zuweisen:

    LRESULT CALLBACK Ship::ShipProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      static Klasse *pThis   = NULL;
      switch (msg)
      {
    	case WM_CREATE:
    	{
    		pThis = (Klasse*) lParam;
    		break;
    	}
    	//weitere Nachrichten...
    	// default Anweisung
      }
    }
    

    Woanders wird pThis nicht mehr zugewiesen. Ich erzeuge auch nur eine Instanz auf meine Klasse.



  • Selbst wenn es eine Singleton-Klasse sein soll, arbeitet man dann nicht auf pThis sondern ruft pThis->methode() auf und macht methode() nicht-statisch.
    Statische Methoden haben gefälligst nicht auf Instanzobjekten zu arbeiten. Da würde ich keine minute auf Fehlersuche verschwenden, solange ich so einen Murks mache.



  • Versuch mal sowas:

    class my_singleton {
    private:
      my_singleton() { }
      my_singleton &instance() {
        static my_singleton me;
        return me;
      }
    
      void do_method() {
        // Code
      }
    
    public:
      static void method() { instance().do_method(); }
    };
    


  • Ja? Und wo muss ich jetzt deswegen Instanzmethoden statisch machen und die dann über me irgendwas ändern lassen?
    Das muss man nie machen. Methoden, die das Objekt benutzten haben nicht statisch zu sein und trotzdem im Objekt rumzupfuschen. Es gibt sowas wie den Grundsatz, undurchsichtige Seiteneffekte und unnötige Fehlerquellen zu vermeiden.



  • Das Problem ist, dass die Funktion gleichzeitig auch eine Callbackfunction ist und da kommst du nicht mit Methoden weiter (Beschwerden bitte an MS).

    Jedoch ist ein gobaler Pointer nicht die Lösung. Such mal nach SetWindowLong und GetWindowLong, damit kannst du ein 32 Bit Wert mit einem HWND assosiren. Setzt den einfach auf this und dann ist das Problem mit den mehreren Instancen gelöst.

    Nun vergiss mal WM_CREATE und setzt den Code dochthin wo er hingehört, das heist hinter den CreateWindow-Aufruf im Konstruktor.

    Wenn dies nicht dein Problem löst, dann musst du woll noch etwas konkreter werden.



  • Es gibt auch Methodenpointer. Außerdem kann man (wenn es schon ne statische Methode sein muss) immer noch die Instanz als Parameter übergeben. Aber heimlich was über pThis zu ändern ist sicherlich kein gutes Design und endlose Quelle für mögliche hard-to-find Bugs.



  • Optimizer schrieb:

    Es gibt auch Methodenpointer. Außerdem kann man (wenn es schon ne statische Methode sein muss) immer noch die Instanz als Parameter übergeben. Aber heimlich was über pThis zu ändern ist sicherlich kein gutes Design und endlose Quelle für mögliche hard-to-find Bugs.

    Sagte ich nicht Beschwerden an MS? Jendenfals helfen Methodenpointer hier nicht weiter da die WinAPI einen Funktionspointer haben will/muss, und mit ein Methodenpointer ist kein Funktionspointer wegen der heimlichen übergabe von this als Parameter.



  • und mit ein Methodenpointer ist kein Funktionspointer wegen der heimlichen übergabe von this als Parameter

    in der winapi faq ist ein ansatz, mit dem genau das möglich ist.



  • Ich hab den 4 Seiten Thread einmal überflogen und eine Schlussfolgerung konnte ich nicht erkennen. Aber wer umbedingt den this pointer als this Pointer vorliegen haben will, also wem dieser Syntaxzucker nicht völlig schnuppe ist kann das so machen:

    class BaseWindow{
    private:
      static LRESULT CALLBACK DummyProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
      static void RegisterClass();
    
      HWND hWnd;
    
    public:
      BaseWindow();
      ~BaseWindow();
    
      virtual LRESULT WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
    };
    
    void BaseWindow::RegisterClass()
    {
      static bool registered = false;
      if(!registered)
      {
        registered = true;
        //register
      }
    }
    
    BaseWindow::BaseWindow()
    {
      RegisterClass();
      hWnd = CreateWindow(..., this);
    }
    
    BaseWindow::~BaseWindow()
    {
      DestroyWindow(hWnd);
    }
    
    LRESULT CALLBACK BaseWindow::DummyProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      Window*wbWin = (Window*)GetWindowLong(hwnd, GWL_USERDATA);
      if(wbWin != NULL)  
        return wbWin->WndProc(hwnd, msg, wParam, lParam);
      else 
        return DefWindowProc(hwnd, msg, wParam, lParam)
    }
    
    LRESULT BaseWindow::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      //sämtliche Member wie gewohnt zugänglich
      switch(msg)
      {
        ...
      }
    }
    


  • erinnert mich irgendwie an eine Klasse, die ich mal im winapi teil gepostet hab:

    class SubClass{
        private:
            static long BaseWindowProc(HWND hwnd,unsigned int message,unsigned int wParam,unsigned int lParam){
                callback oldCallback=reinterpret_cast<callback>(GetProp(hwnd,"oldCallback"));
    
                SubClass* callingClass=reinterpret_cast<SubClass*>(GetProp(hwnd,"this"));
                return callingClass->WindowProc(oldCallback,hwnd,message,wParam,lParam);
            }
            HWND subWindow;
            callback oldCallback;
        protected:
            virtual long WindowProc(callback oldCallback,HWND hwnd,unsigned int message,unsigned int wParam,long lParam)=0;
        public:
            SubClass(HWND window):subWindow(window){
                if(!window){
                    throw(Exception::CreationFailed("couldn't create subclass->Nullpointer",__LINE__,__FILE__));
                }
                //get old callback
                oldCallback=reinterpret_cast<callback>(GetWindowLongPtr(subWindow,GWLP_WNDPROC));
    
                //set properties
                SetProp(subWindow,"oldCallback",oldCallback);
                SetProp(subWindow,"this",this);
    
                //set new callback
                SetWindowLongPtr(subWindow,GWLP_WNDPROC,reinterpret_cast<long>(BaseWindowProc));
            }
            virtual ~SubClass(){
                //reset window
                SetWindowLongPtr(subWindow,GWLP_WNDPROC,reinterpret_cast<long>(oldCallback));
                RemoveProp(subWindow,"oldCallback");
                RemoveProp(subWindow,"this");
            }
            HWND getHandle(){
                return subWindow;
            }
        };
    

    nachteil deiner Klasse: sie kann die funktionalität eines buttons(zb) nicht erhalten.
    Das Klassendesign hab ich aber dann verworfen,da es einige probleme damit gab, zb, dass man in teufelsküche kam,wenn man versuchte eine subclass mit dem von Gethandle gelieferten HWND zu erstellen. Die Designschwäche war stark genug, dass ich mich davon wieder abgewandt hab(auch wenn es möglich wäre,das design zu korrigieren,es lohnt nicht, der aufwand wird viel zu groß,und das ganze endet in lustigen undurchsichtigen rekursionen)



  • Danke für eure Antworten.
    Ich werd mal einiges probieren.


Anmelden zum Antworten