Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

26.07.2011, 14:39

Memberfunktion an struct übergeben

Guten Tag ^^
Ich steh mal wieder an und weiß mir nicht zu helfen ...
Ich habe das Problem, dass ich einer Struktur einen Funktionspointer haben will, dem ich eine Memberfunktion einer beliebigen Klasse übergeben kann.
Ich habe gedacht, dass das mit einem normalen Funktionspointer funktioniert, musste aber feststellen, das das so nicht geht ^^

Ich würde gerne wissen, ob es überhaupt möglich ist, einem Funktionspointer in einer struct (die sich selber in einer anderen Klasse befindet) eine Memberfunktion einer beliebigen anderen Klasse zu übergeben?

Hier mal mein Codeprinzip, das ich versucht habe: (SFML1.6 wird verwendet)

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class CGui
{
    private:
        struct SButton
        {
            friend CGui;
            SButton() : bActivate(false), sName(""), fPosition(0.0f, 0.0f) {} //Konstruktor
            
            SButton(const string &s_Name, void (*p_ActionListener) ()) : bActivate(false)  //Konstruktor zum Anlegen eines neuen Buttons
            {
                sName.SetText(s_Name); 
                sName.SetSize(20.0f);
                sName.SetColor(Color(14,14,14));
                pActionListener = *p_ActionListener;

                //cout << pActionListener << " " << p_ActionListener << endl;
            }

            void (*pActionListener) ();

            bool bActivate; //Ob der Button aktiviert wurde
            String sName; //Name des Buttons
            Vector2f fPosition; //Position relativ zum Interface
        };
}

class CMap
{
    public:
        CMap()
        {
            //GUI Init
            m_GUI.Init();
            m_GUI.AddButton("Button1", &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button2", &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button3", &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button4", &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button5", &CMap::GUI_ActionListener);
        }
    private:
        CGui m_GUI; //GUI für die Elementsetzung
        void GUI_ActionListener() {}
}


Meine Idee hinter dem ganzen ist wie ein Action - Listener - System.
Ich drücke einen Button und die Funktion wird aufgerufen.

Ist das prinzipiell überhaupt so möglich, wie ich mir das vorstelle oder gehe ich da mal wieder etwas falsch an?

Danke schonmal im voraus und liebe Grüße,
Ombalat

Edit: AddButton ruft den überladenen Konstruktor der Struktur auf

TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

2

26.07.2011, 15:04

Prinzipiell ist es möglich, MyGUI zum Beispiel macht davon gebrauch. wies geht steht hier: codeproject

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

3

26.07.2011, 15:20

Klar geht das, brauchst aber die Instanz dazu, nicht nur den Funktions-Pointer.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

4

27.07.2011, 15:00

Hallo nochmal ... vielen Dank für den Link.
Ich habe jetzt ein wenig herumgebastelt und denke, das ich das Problem jetzt fast gelöst habe. Ich bekomme jedoch den Aufruf des Konstruktors der Stuktur beim erstellen noch nicht richtig hin :(
Er beschwert sich bei dem this zeiger und dem ActionListener immer noch. Hoffe, ihr könnt mir nocheinmal weiterhelfen

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class CGui
{
    struct SButton;

    class SomeClass; //Die Klasse, von der der ActionListener aufgerufen wird
    typedef void (SomeClass::* ActionListener)(); //Typedef für Memberfunktionspointer

    public:
        void AddButton(const string &sName, SomeClass *p_Class, ActionListener _listener)
        {
            SButton* tempButton = new SButton(sName, p_Class, _listener); //Button laden
            m_vButtons.push_back(*tempButton);
        }

    private:
        vector<SButton> m_vButtons; //Vector, der die Buttons beinhaltet

        struct SButton
        {
            friend CGui;
            SButton() : bActivate(false), sName(""), fPosition(0.0f, 0.0f) {} //Konstruktor

            SButton(const string &s_Name, SomeClass *p_Class, ActionListener _listener) : bActivate(false)  //Konstruktor zum Anlegen eines neuen Buttons
            {
                sName.SetText(s_Name); 
                sName.SetSize(20.0f);
                sName.SetColor(Color(14,14,14));
                
                pClass = p_Class; //Die Klasse definieren
                listener = _listener; //Den Funktionspointer der Klasse definieren

                //cout << pActionListener << " " << p_ActionListener << endl;
            }

            void RunActionListener() { (pClass->*listener)(); }

            SomeClass *pClass;
            ActionListener listener;

            bool bActivate; //Ob der Button aktiviert wurde
            String sName; //Name des Buttons
            Vector2f fPosition; //Position relativ zum Interface
        };
}

class CMap
{
    public:
        CMap()
        {
            //GUI Init
            m_GUI.Init();
            m_GUI.AddButton("Button1", this, &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button2", this, &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button3", this, &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button4", this, &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button5", this, &CMap::GUI_ActionListener);
        }
    private:
        CGui m_GUI; //GUI für die Elementsetzung
        void GUI_ActionListener() {}
}


Liebe Grüße,
Ombalat

marfi

Treue Seele

Beiträge: 100

Wohnort: Schwerte

  • Private Nachricht senden

5

27.07.2011, 15:18

Wenn du deine Memberfunktion als static deklarierst kannst du sie ohne Instanz übergeben.



C-/C++-Quelltext

1
Class::Mebmberfunc()




Dann meckert dein compiler auch nicht mehr.

6

27.07.2011, 15:27

Als zweiter Parameter von AddButton wird ein Zeiger auf SomeClass erwartet, this in CMap ist aber vom Typ CMap*. Selbes beim Zeiger auf die Memberfunktion. Wohl ein bisschen zu viel copy & paste?

7

27.07.2011, 16:47

Nur weil ich mich an der seite orientiert habe heißt das noch lange nicht, dass ich mich damit nicht auseinandergesetzt habe und es nicht durchdacht habe ... deshalb wollte ich ja nochmal nachfragen, wie ich das jetzt initialisieren kann ... genaugenommen erwartet er doch eine CGui::SomeClass Pointer genauso wie einen CGui::SomeClass::* Memberfunktions - Pointer? Die kann ich aber nicht in meiner CMap initialisierung verwenden, weil ich ja dort die Funktion liegen habe, die ich aufrufen will

8

27.07.2011, 17:52

Zitat

Nur weil ich mich an der seite orientiert habe heißt das noch lange nicht, dass ich mich damit nicht auseinandergesetzt habe

Ok, nicht zu ernst nehmen ;)

Wie gesagt macht das doch mit SomeClass gar keinen Sinn, da du gar keine Klasse SomeClass hast? Ich würde es mal so versuchen (nicht getestet; Änderungen mit Kommentaren markiert):

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class CGui
{
    struct SButton;

    class CMap;//###
    typedef void (CMap::* ActionListener)();//###

    public:
        void AddButton(const string &sName, CMap *p_Class, ActionListener _listener)//###
        {
            SButton* tempButton = new SButton(sName, p_Class, _listener);
            m_vButtons.push_back(*tempButton);
delete tempButton; // push_back macht eine Kopie
        }

    private:
        vector<SButton> m_vButtons;

        struct SButton
        {
            friend CGui;
            SButton() : bActivate(false), sName(""), fPosition(0.0f, 0.0f) {}

            SButton(const string &s_Name, CMap *p_Class, ActionListener _listener) : bActivate(false)  //###
            {
                sName.SetText(s_Name); 
                sName.SetSize(20.0f);
                sName.SetColor(Color(14,14,14));
                
                pClass = p_Class;
                listener = _listener;
            }

            void RunActionListener() { (pClass->*listener)(); }

            CMap *pClass;//###
            ActionListener listener;

            bool bActivate; 
            String sName; 
            Vector2f fPosition; 
        };
}; // Strichpunkt

class CMap
{
    public:
        CMap()
        {
            m_GUI.Init();
            m_GUI.AddButton("Button1", this, &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button2", this, &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button3", this, &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button4", this, &CMap::GUI_ActionListener);
            m_GUI.AddButton("Button5", this, &CMap::GUI_ActionListener);
        }
    private:
        CGui m_GUI;
        void GUI_ActionListener() {}
}; // Strichpunkt

Bei Fehlern wenn möglich Zeile und Beschreibung angeben.

9

27.07.2011, 18:16

Ja, ich denke, dass es so funktionieren könnte.
Ich möchte die AddButton funktion aber in einer beliebigen (vorher nicht bekannten) Klasse aufrufen können.
Das geht so ja (wenn) nur für die Map Klasse ...
Wäre an der stelle dann vielleicht ein Template für die Klasse, die jetzt als CMap drinnen steht, angebracht (also class CMap --> template<class CMap>) oder gleich eine Template Klasse CGui?

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

10

28.07.2011, 07:52

Benutz doch ein Interface IActionListener anstelle von CMap.
Klassen, die das Interface implementieren, müssen dann eine bestimmte Methode bereitstellen, und die rufst Du auf, wenn der Button geklickt wurde.
Oder Du benutzt Boost::function (müsstest Du aber wohl kapseln).

Werbeanzeige