Problem mit static und non-static Memberfunktionen



  • Hallo

    Ich hab das Problem, dass ich innerhalb einer statischen Memberfunktion meiner Klasse, eine nicht-statische Memberfunktion der selbigen Klasse aufrufen muss.

    Um mein Problem zu verdeutlichen, hier ein stark vereinfachtes Codebeispiel:

    class CMyClass
    {
    public:
    	static void func1(){
    		func2();
    	}
    	void func2(){
    	}
    };
    

    Wie kann ich da rangehen? Gibts irgendwelche Workarounds?

    Danke schon mal.



  • Du verstehst aber schon den Unterschied zwischen statischer und nichtstatischer Funktion, oder?

    Um das zu ermöglichen, musst Du in der statischen Funktion irgendwo eine Instanz von CMyClass herbekommen. Entweder als Parameter der statischen Funktion (dann kannst Du sie aber auch gleich nichtstatisch machen), oder als lokales Objekt.



  • class Bla
    {
    public:
        static void foo(Bla& laber)
        {
            laber.bar();
        }
        void bar(){ }
    
    };
    
    //...
    Bla bla;
    Bla::foo(bla);
    

    Memberfunktionen brauchen ein Objekt, für die sie aufgerufen werden...



  • Das ganze sollte ja nur eine starke Vereinfachung meines Problems darstellen.
    Ich werd dann mal diese Klasse etwas genauer beschreiben.

    Innerhalb der Klasse brauche ich einen Timer, dafür verwende ich halt TimerProc.
    Dann hab ich natürlich auch noch ne Funktion die den Timer startet, diese setzt den Timer ganz normal mit SetTimer().

    Damit ich allerdings mit SetTimer auf meine TimerProc zeigen kann, muss eben die TimerProc statisch sein, ansonsten funktioniert das mit SetTimer() leider nicht.

    So weit so gut, mein Problem is jetzt, dass ich nun zwar den Timer setzen kann, allerdings wegen dem static bei der TimerProc keine anderen Members meiner Klasse mehr innerhalb der TimerProc() aufrufen kann, was jetzt auch wieder blöd ist.

    So ungefähr sieht das aus...

    class CMyClass
    {
    public:
    	void SetMyTimer(){
    		SetTimer(NULL, NULL, 1000, TimerProc);
    	}
    
    private:
    	void MyFunction(){
    		// ...
    	}
    	static void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime){
    		MyFunction();
    	}
    };
    


  • Da hast du aber ein Design Problem. Wenn du jetzt eine statische Funktion hast, dann ist es ja gerade der Clue, dass es Objektunabhängig ist. Wenn du Infos über ein Objekt haben musst, dann musst du wohl oder übel übergeben oder ne nicht-statische Memberfunktion draus machen.

    Wieso muss den TimerProc auf das Objekt zugreifen? Ich würde eher mal an dem arbeiten.



  • Unsicherbartes Fenster, SetWindowLong, GetWindowLong



  • Man könnte auch die anderen Timer-Sachen aus der WinAPI nutzen, mir fallen grade aber nicht die Funktionsnamen ein.



  • drakon schrieb:

    Da hast du aber ein Design Problem. Wenn du jetzt eine statische Funktion hast, dann ist es ja gerade der Clue, dass es Objektunabhängig ist. ...
    Wieso muss den TimerProc auf das Objekt zugreifen? Ich würde eher mal an dem arbeiten.

    Stimmt !
    Du kannst Dir allerdings mit einem globalen Objekt behelfen (so häßlich das auch ist):

    struct CMyClass {
       void MyFunction(){ cout << "MyFunction\n"; }
    };
    
    static CMyClass globMyClass;
    
    void TimerProc(){
       globMyClass.MyFunction();
    }
    
    int main() {
       SetTimer(TimerProc);
       return 0;
    }
    

    Aber wie schon oben erwähnt: Wenn das Konstrukt eigentlich nicht dafür gedacht ist, mit Objekten zu arbeiten, kann das derbe in die Hose gehen.... (z.B. bzgl. Multithreading oder Speicherkopien oder ....)

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Du kannst Dir allerdings mit einem globalen Objekt behelfen (so häßlich das auch ist):

    Ich hab mir noch überlegt, ob ich schreiben soll, dass er ja nicht auf die Idee kommen soll da jetzt ein globales Objekt zu nehmen. :p


  • Administrator

    http://msdn.microsoft.com/en-us/library/ms644906.aspx

    Wieso lässt du nicht einfach die TIMERPROC Funktion weg und behandelst die WM_TIMER Message? Eine Nachrichtenschleife wirst du ja wohl haben und wenn dann die enstprechende WM_TIMER Nachricht kommt, kannst du sie im aktuellen Thread an das richtige Objekt weiterleiten.

    -> Korrekte Anwendung der SetTimer Funktion, das ist die Lösung 😉

    Grüssli



  • Da ich sowieso ohne Multithreading arbeite hab ichs jetzt so in der Art gelöst:

    class CMyClass
    {
    public:
    	void SetMyTimer(){
    		SetTimer(NULL, NULL, 1000, TimerProc);
    	}
    	void MyFunction(){
    
    	}
    
    private:
    	static VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime){
    			CMyClass *p = (CMyClass*)pObject;
    			p->MyFunction();
    	}
    	static void * pObject;
    
    };
    

    Im Falle des Falls könnte ich ja das ganze dann immer noch mit CRITICAL_SECTION und EnterCriticalSection() bzw LeaveCriticalSection() absichern.

    Besten Dank an alle. 🙂



  • 😮 😮 😮
    Sorry, aber das ist ja grausig !!

    Warum ein void* mit Rumcasterei (und dann noch C-Style) und vermutlich auch noch auf den Heap geworfen .... ?

    Zum Einen kannst Du auch direkt einen CMyClass* nehmen und zum Anderen am Besten direkt ein Objekt statt eines Pointers und .... und ... und ....

    (das Ganze krmapfhaft in eine Klasse zu puhlen, ist eh' keine besonders dolle Idee: Es besteht z.B. ein Unterschied zwischen "einem Ding" und "dem, der mit diesem Ding etwas macht" - außerdem es überflüssig TimerProc() zur Memberfunktion zu machen)

    Ich meine, letztlich kann Dich hier keiner zwingen, aber an Deiner Stelle würde ich den Rat der Leute hier ernstlich in Erwägung ziehen ... die meisten sagen das nicht, um Dir die Arbeit künstlich schwerer zu machen, sondern aus Erfahrung (oft einer, die sie Dir ersparen wollen).

    Gruß,

    Simon2.



  • Nach reichlichen Überlegungen hab ich mich jetzt doch entschlossen dann etwas am Design meines Programms zu ändern.
    Ich hab jetzt den Timer aus der Klasse rausgenommen und stattdessen ins Hauptprogramm mit reingenommen.
    Das macht die Dinge, die der Timer so machen muss, zwar etwas komplizierter, aber wenigstens kann mir dann keiner mehr was wegen dem Design vorwerfen. 😛



  • 96fff schrieb:

    ...wenigstens kann mir dann keiner mehr was wegen dem Design vorwerfen. 😛

    Allein schon deshalb, weil Du es uns nicht mehr zeigst. :p 😉

    Gruß,

    Simon2.


Log in to reply