Question

J'essaie de transmettre une fonction membre d'une classe à une fonction qui prend un pointeur de classe de fonction membre. Le problème que j'ai est que je ne suis pas sûr de savoir comment faire ceci correctement dans la classe en utilisant le pointeur this. Quelqu'un a-t-il des suggestions?

Voici une copie de la classe qui transmet la fonction membre:

class testMenu : public MenuScreen{
public:

bool draw;

MenuButton<testMenu> x;

testMenu():MenuScreen("testMenu"){
    x.SetButton(100,100,TEXT("buttonNormal.png"),TEXT("buttonHover.png"),TEXT("buttonPressed.png"),100,40,&this->test2);

    draw = false;
}

void test2(){
    draw = true;
}
};

La fonction x.SetButton (...) est contenue dans une autre classe, où "objet". est un modèle.

void SetButton(int xPos, int yPos, LPCWSTR normalFilePath, LPCWSTR hoverFilePath, LPCWSTR pressedFilePath, int Width, int Height, void (object::*ButtonFunc)()) {

    BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height);

    this->ButtonFunc = &ButtonFunc;
}

Si quelqu'un a des conseils sur la manière d'envoyer correctement cette fonction afin de pouvoir l'utiliser ultérieurement.

Était-ce utile?

La solution

Pour appeler une fonction membre par un pointeur, vous avez besoin de deux éléments: un pointeur sur l'objet et un pointeur sur la fonction. Vous avez besoin des deux dans MenuButton :: SetButton ()

template <class object>
void MenuButton::SetButton(int xPos, int yPos, LPCWSTR normalFilePath,
        LPCWSTR hoverFilePath, LPCWSTR pressedFilePath,
        int Width, int Height, object *ButtonObj, void (object::*ButtonFunc)())
{
  BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height);

  this->ButtonObj = ButtonObj;
  this->ButtonFunc = ButtonFunc;
}

Vous pouvez ensuite appeler la fonction à l'aide des deux pointeurs:

((ButtonObj)->*(ButtonFunc))();

N'oubliez pas de passer le pointeur sur votre objet avec MenuButton :: SetButton () :

testMenu::testMenu()
  :MenuScreen("testMenu")
{
  x.SetButton(100,100,TEXT("buttonNormal.png"), TEXT("buttonHover.png"),
        TEXT("buttonPressed.png"), 100, 40, this, test2);
  draw = false;
}

Autres conseils

Je recommanderais vivement boost :: bind et boost :: function à ces tâches.

Voir Passer et appeler une fonction membre (boost :: bind / boost :: function?)

Je sais que c'est un sujet assez ancien. Mais il existe un moyen élégant de gérer cela avec c ++ 11

#include <functional>

déclarez votre pointeur de fonction comme ceci

typedef std::function<int(int,int) > Max;

déclarez votre fonction votre passe cette chose dans

void SetHandler(Max Handler);

supposons que vous lui passiez une fonction normale, vous pouvez l'utiliser comme d'habitude

SetHandler(&some function);

supposons que vous ayez une fonction membre

class test{
public:
  int GetMax(int a, int b);
...
}

dans votre code, vous pouvez le transmettre en utilisant std :: placeholders comme ceci

test t;
Max Handler = std::bind(&test::GetMax,&t,std::placeholders::_1,std::placeholders::_2);
some object.SetHandler(Handler);

Ne seriez-vous pas mieux servi en utilisant OO standard. Définissez un contrat (classe virtuelle) et implémentez-le dans votre propre classe, puis transmettez une référence à votre propre classe et laissez le destinataire appeler la fonction de contrat.

En utilisant votre exemple (j'ai renommé la méthode 'test2' en 'buttonAction'):

class ButtonContract
{
  public:
    virtual void buttonAction();
}


class testMenu : public MenuScreen, public virtual ButtonContract
{
  public:
    bool draw;
    MenuButton<testMenu> x;

    testMenu():MenuScreen("testMenu")
    {
      x.SetButton(100,100,TEXT("buttonNormal.png"), 
              TEXT("buttonHover.png"), 
              TEXT("buttonPressed.png"), 
              100, 40, &this);
      draw = false;
    }

    //Implementation of the ButtonContract method!
    void buttonAction()
    {
      draw = true;
    }
};

Dans la méthode du destinataire, vous stockez la référence dans un ButtonContract. Lorsque vous souhaitez exécuter l'action du bouton, appelez simplement la méthode 'buttonAction' de cet objet ButtonContract stocké.

Dans les rares cas où vous développez avec Borland C ++ Builder et que l’écriture de code spécifique à cet environnement de développement (c’est-à-dire un code qui ne fonctionne pas avec d’autres compilateurs C ++) ne vous dérange pas, vous pouvez utiliser le mot clé __closure. J'ai trouvé un petit article sur les fermetures de C ++ Builder . Ils sont principalement destinés à être utilisés avec Borland VCL.

D'autres vous ont dit comment le faire correctement. Mais je suis surpris que personne ne vous dise que ce code est réellement dangereux:

this->ButtonFunc = &ButtonFunc;

Comme ButtonFunc est un paramètre, il sera hors de portée lorsque la fonction reviendra. Vous prenez son adresse. Vous obtiendrez une valeur de type void (object :: ** ButtonFunc) () ( pointeur sur un pointeur sur une fonction membre ) et l'affectez à ceci - > ButtonFunc. Au moment où vous utiliseriez ce bouton - > ButtonFunc, vous tenteriez d'accéder au stockage du paramètre local (qui n'existe plus à présent) et votre programme se bloquerait probablement.

Je suis d'accord avec la solution de Commodore. Mais vous devez changer sa ligne en

((ButtonObj)->*(ButtonFunc))();

puisque ButtonObj est un pointeur à un objet.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top