Oui.
Considérez la fonction suivante:
int f(char a, float b);
Le type de cette fonction est différent s'il s'agit d'une fonction ordinaire ou d'un fonction membre non statique d'une classe classe:
[ Haut | Bas | Rechercher ]
Ne le faites pas.
Parce qu'un pointeur de fonction membre est sans signification sans un objet sur laquelle l'invoquer, vous ne pouvez pas faire cela directement (Si X Windows était réécrit en C++, il passerai probablement des références vers des objets, et non pas seulement des pointeurs de fonctions; naturellement ces objets devraient incorporer la fonction requise et probablement bien d'autre chose).
Comme pour les patchs pour des logiciels existant, utilisé une fonction globale (non membre) comme enveloppe qui prend un objet obtenu par une autre technique (dans une variable globale par exemple). Le fonction globale appliquera le pointeur de fonction membre a cette objet.
E.g., supposons que vous voulez appeler Fred::memberFunction() sur un interruption:
class Fred {
public:
void memberFunction();
statique void staticMemberFunction(); // un fonction membre
static peut la gérer
// ...
};
// La fonction enveloppe utilise une variable comme objet:
Fred* object_which_will_handle_signal;
void Fred_memberFunction_wrapper()
{
object_which_will_handle_signal->memberFunction();
}
int main()
{
/* signal(SIGINT, Fred::memberFunction); */
// Ne fonctionne pas
signal(SIGINT, Fred_memberFunction_wrapper); // OK
signal(SIGINT, Fred::staticMemberFunction);
// Aussi OK
}
Note: Les pointeurs de fonctions membres static ne nécessitent pas d'objets pour les invoquer, aussi les pointeurs de fonctions membres static on un type compatible avec les pointeurs de fonctions.
[ Haut | Bas | Rechercher ]
Les fonctions membres non statiques ont un paramètre caché qui correspond au pointeur this. Le pointeur this pointe vers l'instance de l'objet implicite. Le gestionnaire matériel/logiciel d'interruption n'est pas capable de fournir l'argument pointeur this a la routine. Vous devez utiliser une fonction "normal" (fonction non membre) ou une fonction membre statique comme gestionnaire d'interruption.
Une solution possible est d'utiliser une fonction membre static membre comme gestionnaire d'interruption, cette routine devra connaître la pair objet/pointeur de fonction membre qui doit être appelé lors de l'interruption. Ainsi l'effet est qu'une fonction membre est invoqué par interruption mais que pour des raisons techniques vous avez besoin de l'appel a une fonction intermédiaire en premier lieu.
[ Haut | Bas | Rechercher ]
Réponse détaillée: En C++, les fonctions membres possèdent un paramètre supplémentaire implicite qui pointe vers l'objet (le pointeur this dans les fonctions membres). Les fonctions C normales peuvent être vu comme ayant une convention d'appel différentes des fonctions membres, aussi leurs types (pointeur de fonction membre contre pointeur de fonction) sont différents et incompatibles. Le C++ introduit un nouveau type de pointeur appelé pointeur de membre, qui peut être utilisé seulement en fournissant un objet.
NOTE: N'essayez pas de tenter de "transtyper" un pointeur de fonction membre vers un pointeur de fonction; le résultat est indéfini et probablement désastreux. E.g., un pointeur de fonction membre n'est pas requis de contenir l'adresse machine de la fonction appropriée. Comme nous l'avons dit dans le dernier exemple, si vous avez un pointeur de fonction C normal, utilisez soit une fonction non membre soit une fonction membre static (de classe).
[ Haut | Bas | Rechercher ]
Voici comment créer le typedef:
class Fred {
public:
int f(char x, float
y);
int g(char
x, float y);
int h(char x, float y);
int i(char x, float y);
// ...
};
// FredMemberFn pointe vers un membre de Fred qui
prend (char,float)
typedef int (Fred::*FredMemberFn)(char, float);
Voici comment créer la macro #define (normalement je n'aime pas les macros #define , mais ceci est un des rares cas ou une macro facilitera l'écriture et la lisibilité de votre code):
#define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember))
Voici un exemple d'utilisation:
void userCode(Fred&
fred, FredMemberFn memFn)
{
callMemberFunction(fred,memFn)('x',
3.14);
// devrait normalement être: (fred.*memFn)('x', 3.14);
}
Je recommande fortement l'utilisation de cette méthode. Dans le monde réel l'utilisation des pointeurs de fonction membre est beaucoup plus complexe que dans l'exemple donné, et la différence en terme de facilité d'écriture et de lisibilité est significative. comp.lang.c++ a enduré des centaines et des centaines de messages de programmeurs ayant eu des problèmes de syntaxe avec des pointeurs de fonctions membres. La plupart de ces erreurs ne se serait pas produite en utilisant la méthode ci-dessus.
[ Haut | Bas | Rechercher ]
D'abord écrivez un typedef:
class Fred {
public:
int f(char x, float
y);
int g(char
x, float y);
int h(char x, float y);
int i(char x, float y);
// ...
};
// FredMemberFn pointe vers un membre de Fred qui
prend (char,float)
typedef int (Fred::*FredMemberFn)(char, float);
Ce qui permet d'écrire le tableau de pointeur de fonction membre directement:
FredMemberFn a[4] = { &Fred::f, &Fred::g, &Fred::h, &Fred::i };
Ensuite, définissez la macro callMemberFunction:
#define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember))
Ce qui permet d'appeler une des fonctions membres sur l'objet "fred" directement:
void userCode(Fred& fred, int memberFunctionNum)
{
// pré-supose que memberFunctionNum est compris entre
0 and 3 inclus:
callMemberFunction(fred, a[memberFunctionNum]) ('x', 3.14);
}
[ Haut | Bas | Rechercher ]
Ecrire à l'auteur,
au traducteur,
ou en savoir plus sur la traduction.
C++ FAQ Lite fr |
Table des matières |
Index |
A propos de l'auteur |
© |
Téléchargez votre propre copie ]
Dernière révision Sun Apr 13 23:54:31 PDT 2003