2011-01-29 1 views
0

J'ai donc une classe comme:ayant "typedef void FuncCharPtr" dans une classe comment alimenter la fonction qui utilise ce typedef avec des fonctions non statiques?

class IGraphElement{ 

    // We should define prototype of functions that will be subscribers to our data 
    typedef void FuncCharPtr(char*, int) ; 

public: 
    // Function for adding subscribers functions 
    void Add(FuncCharPtr* f) 
    { 
      //... 
    } 
}; 

et une autre classe comme

#include "IGraphElement.h" 

class simpleRendererGraphElement : public IGraphElement 
{ 
    public: 
    IGraphElement* charGenerator; 
    // we owerrite init 
    void Init(IGraphElement* CharGenerator) 
    { 
     charGenerator = CharGenerator; 
     //we can to subscribe some function to our data generator 
     charGenerator->Add(renderCastedData); // and here we receive C3867 
    } 
    void renderCastedData(char* castedChar, int castedCharLength) // our event system receives functions declared like void FuncCharPtr(char*, int) ; 
    { } 
}; 

pourquoi nous obtenons erreur C3867 et comment corriger ne pas faire des fonctions statiques?

+0

'FuncCharPtr' est un terme inapproprié: ce n'est pas du tout un type de pointeur, c'est un type de fonction. Un type de pointeur ressemblerait à 'typedef void (* FuncCharPtr) (char *, int);'. –

Répondre

1

renderCastedData est une fonction membre non statique. Son type est

void (simpleRendererGraphElement::*)(char*, int) 

Pour appeler, vous devez avoir une instance de simpleRendererGraphElement pour le paramètre this. Il y a beaucoup de solutions à ce problème. Une option serait de faire Add un modèle de fonction qui prend tout ce qui peut être appelé avec un char* et un paramètre int:

template <typename Function> 
void Add(Function f) 

alors vous pouvez écrire un objet de fonction pour envelopper l'appel:

struct RenderCastedDataFunctor 
{ 
    simpleRendererGraphElement* obj_; 

    RenderCastedDataFunctor(simpleRendererGraphElement* obj) 
     : obj_(obj) { } 

    void operator()(char* castedChar, int castedCharLength) 
    { 
     obj_->renderCastedData(castedChar, castedCharLength); 
    } 
}; 

et de votre fonction Init vous pouvez appeler

charGenerator->Add(RenderCastedDataFunctor(this)); 

(Le bind etLes bibliothèquesde Boost, C++ TR1 et C++ 0x fournissent une forme généralisée de ce modèle, vous permettant de lier des arguments à toute entité appelable et de stocker ces entités appelables liées pour une utilisation ultérieure. Cette approche particulière ici est juste une version simplifiée qui devrait fonctionner sans bibliothèques supplémentaires ou éventuellement non supportées.)

+0

Ça ne marcherait pas avec sortir RenderCastedDataFunctor après avoir fait Ajouter un modèle? Et pouvons-nous spécifier nos entrées de fonction de modèle? – Rella

1
typedef void FuncCharPtr(char*, int) ; 

Tout d'abord, ci-dessus doivent être cela,

typedef void (*FuncCharPtr)(char*, int) ; 

Deuxièmement, renderCastedData n'est pas un pointeur de fonction; c'est un pointeur de fonction-membre. Donc, il y a une différence. C'est le type est void (simpleRendererGraphElement::*)(char*, int);, pas le type ci-dessus!

+0

@Downvoter: vous voulez expliquer la raison? – Nawaz

+0

Je ne suis pas abattu - j'ai voté. Et j'ai une question - comment faire typedef être un modèle de sorte que tout type de pointeur qui prend (char *, int) arguments serait "Addable"? – Rella

+0

@Kabumbus: vous ne pouvez pas écrire de typedef générique. ce n'est pas autorisé. mais ne vous inquiétez pas, vous avez une meilleure solution: vous pouvez écrire un foncteur générique pour atteindre la même chose! – Nawaz

1

Une fonction membre n'est pas une fonction régulière et ne peut pas être affectée à un pointeur de fonction ordinaire.

Utilisez la fonction de membre statique si renderCastedData n'a besoin d'être lié à aucune instance de classe. Si renderCastedData doit être lié à une instance de classe, laissez IGraphElement::Add accepter un pointeur de fonction membre et un pointeur vers la classe.

boost :: function et boost :: bind est également un bon choix pour le problème, ils offrent beaucoup plus de flexibilité, mais parfois, il peut être un peu plus lent.

Questions connexes