Comment obtenir un pointeur de fonction pour une fonction membre de classe et appeler ultérieurement cette fonction membre avec un objet spécifique? J'aimerais écrire:
class Dog : Animal
{
Dog ();
void bark ();
}
…
Dog* pDog = new Dog ();
BarkFunction pBark = &Dog::bark;
(*pBark) (pDog);
…
De plus, si possible, j'aimerais également appeler le constructeur via un pointeur:
NewAnimalFunction pNew = &Dog::Dog;
Animal* pAnimal = (*pNew)();
Est-ce possible, et si oui, quelle est la meilleure façon de procéder?
c++
function-pointers
class-method
Tony le poney
la source
la source
Dog dog;
) est plus probablement ce que vous voulez.Réponses:
Lisez ceci pour plus de détails:
la source
*this.*pt2Member
fonctionnerait.*
a une priorité plus élevée sur.*
... Personnellement, j'aurais quand même écritthis->*pt2Member
, c'est un opérateur de moins.pt2ConstMember
àNULL
?(object.*method_pointer)
, nous voulons donc*
qu'ils aient une plus grande priorité.this
est juste utilisé pour démontrer que tout ce que vous appliquez.*
doit être un pointeur vers une instance de la (sous) classe. Cependant, c'est une nouvelle syntaxe pour moi, je ne fais que deviner sur la base d'autres réponses et ressources liées ici. Je suggère une modification pour rendre cela plus clair.Il est plus simple de commencer par un fichier
typedef
. Pour une fonction membre, vous ajoutez le nom de classe dans la déclaration de type:Ensuite, pour appeler la méthode, vous utilisez l'
->*
opérateur:Je ne crois pas que vous puissiez travailler avec des constructeurs comme celui-ci - les ctors et les dtors sont spéciaux. La manière normale de réaliser ce genre de chose serait d'utiliser une méthode de fabrique, qui est essentiellement une fonction statique qui appelle le constructeur pour vous. Voir le code ci-dessous pour un exemple.
J'ai modifié votre code pour faire essentiellement ce que vous décrivez. Il y a quelques mises en garde ci-dessous.
Maintenant, bien que vous puissiez normalement utiliser a
Dog*
à la place d'unAnimal*
grâce à la magie du polymorphisme, le type d'un pointeur de fonction ne suit pas les règles de recherche de la hiérarchie des classes. Ainsi, un pointeur de méthode Animal n'est pas compatible avec un pointeur de méthode Dog, en d'autres termes vous ne pouvez pas affecter aDog* (*)()
à une variable de typeAnimal* (*)()
.La
newDog
méthode statique est un exemple simple de fabrique, qui crée et renvoie simplement de nouvelles instances. Étant une fonction statique, elle a un réguliertypedef
(sans qualificatif de classe).Ayant répondu à ce qui précède, je me demande s'il n'y a pas de meilleur moyen d'atteindre ce dont vous avez besoin. Il existe quelques scénarios spécifiques dans lesquels vous feriez ce genre de chose, mais vous pourriez trouver d'autres modèles qui fonctionnent mieux pour votre problème. Si vous décrivez en termes plus généraux ce que vous essayez d'accomplir, l'esprit-ruche peut s'avérer encore plus utile!
En relation avec ce qui précède, vous trouverez sans aucun doute la bibliothèque de liaison Boost et d'autres modules connexes très utiles.
la source
->*
auparavant, mais maintenant j'espère que je n'en aurai plus jamais besoin :)Je ne pense pas que quiconque ait expliqué ici qu'un problème est que vous avez besoin de " pointeurs membres " plutôt que de pointeurs de fonction normaux.
Les pointeurs de membres vers des fonctions ne sont pas simplement des pointeurs de fonction. En termes d'implémentation, le compilateur ne peut pas utiliser une adresse de fonction simple car, en général, vous ne connaissez pas l'adresse à appeler tant que vous ne savez pas pour quel objet déréférencer (pensez aux fonctions virtuelles). Vous devez également connaître l'objet afin de fournir le
this
paramètre implicite, bien sûr.Cela dit, vous en avez besoin, je dirai maintenant que vous devez vraiment les éviter. Sérieusement, les pointeurs de membres sont une douleur. Il est beaucoup plus sensé de regarder des modèles de conception orientés objet qui atteignent le même objectif, ou d'utiliser un
boost::function
ou quoi que ce soit comme mentionné ci-dessus - en supposant que vous puissiez faire ce choix, c'est-à-dire.Si vous fournissez ce pointeur de fonction vers du code existant, vous avez donc vraiment besoin d' un simple pointeur de fonction, vous devez écrire une fonction en tant que membre statique de la classe. Une fonction membre statique ne comprend pas
this
, vous devrez donc transmettre l'objet en tant que paramètre explicite. Il y avait une fois un idiome pas si inhabituel dans ce sens pour travailler avec l'ancien code C qui a besoin de pointeurs de fonctionPuisqu'il
myfunction
s'agit en réalité d'une fonction normale (mis à part les problèmes de portée), un pointeur de fonction peut être trouvé de la manière C normale.EDIT - ce type de méthode est appelé "méthode de classe" ou "fonction membre statique". La principale différence avec une fonction non membre est que, si vous la référencez depuis l'extérieur de la classe, vous devez spécifier l'étendue à l'aide de l'
::
opérateur de résolution d'étendue. Par exemple, pour obtenir le pointeur de fonction, utilisez&myclass::myfunction
et pour l'appeler, utilisezmyclass::myfunction (arg);
.Ce genre de chose est assez courant lors de l'utilisation des anciennes API Win32, qui étaient à l'origine conçues pour C plutôt que C ++. Bien sûr, dans ce cas, le paramètre est normalement LPARAM ou similaire plutôt qu'un pointeur, et une conversion est nécessaire.
la source
la source
Exemple exécutable minimal
main.cpp
Compilez et exécutez:
Testé dans Ubuntu 18.04.
Vous ne pouvez pas modifier l'ordre des parenthèses ou les omettre. Les éléments suivants ne fonctionnent pas:
GCC 9.2 échouerait avec:
Norme C ++ 11
.*
et->*
sont des opérateurs uniques introduits en C ++ à cet effet, et non présents en C.Projet de norme C ++ 11 N3337 :
.*
et->*
.la source
Je suis venu ici pour apprendre à créer un pointeur de fonction (pas un pointeur de méthode) à partir d'une méthode, mais aucune des réponses ici ne fournit de solution. Voici ce que j'ai trouvé:
Donc, pour votre exemple, vous feriez maintenant:
Edit:
En utilisant C ++ 17, il existe une solution encore meilleure:
qui peut être utilisé directement sans la macro:
Pour les méthodes avec des modificateurs comme
const
vous pourriez avoir besoin de plus de spécialisations comme:la source
La raison pour laquelle vous ne pouvez pas utiliser de pointeurs de fonction pour appeler des fonctions membres est que les pointeurs de fonction ordinaires ne sont généralement que l'adresse mémoire de la fonction.
Pour appeler une fonction membre, vous devez savoir deux choses:
Les pointeurs de fonction ordinaires ne peuvent pas stocker les deux. Les pointeurs de fonction membre C ++ sont utilisés pour stocker a), c'est pourquoi vous devez spécifier explicitement l'instance lors de l'appel d'un pointeur de fonction membre.
la source
Un pointeur de fonction vers un membre de classe est un problème qui convient vraiment à l'utilisation de boost :: function. Petit exemple:
la source
Pour créer un nouvel objet, vous pouvez soit utiliser placement new, comme mentionné ci-dessus, soit demander à votre classe d'implémenter une méthode clone () qui crée une copie de l'objet. Vous pouvez ensuite appeler cette méthode de clonage à l'aide d'un pointeur de fonction membre comme expliqué ci-dessus pour créer de nouvelles instances de l'objet. L'avantage du clone est que parfois vous travaillez avec un pointeur vers une classe de base où vous ne connaissez pas le type de l'objet. Dans ce cas, une méthode clone () peut être plus simple à utiliser. De plus, clone () vous permettra de copier l'état de l'objet si c'est ce que vous voulez.
la source
J'ai fait cela avec std :: function et std :: bind ..
J'ai écrit cette classe EventManager qui stocke un vecteur de gestionnaires dans un unordered_map qui mappe les types d'événement (qui sont simplement const unsigned int, j'ai une grande énumération à la portée de l'espace de noms) à un vecteur de gestionnaires pour ce type d'événement.
Dans ma classe EventManagerTests, j'ai configuré un gestionnaire d'événements, comme ceci:
Voici la fonction AddEventListener:
Voici la définition du type EventHandler:
Puis de retour dans EventManagerTests :: RaiseEvent, je fais ceci:
Voici le code pour EventManager :: RaiseEvent:
Cela marche. Je reçois l'appel dans EventManagerTests :: OnKeyDown. Je dois supprimer les vecteurs au moment du nettoyage, mais une fois que je le fais, il n'y a pas de fuites. Le déclenchement d'un événement prend environ 5 microsecondes sur mon ordinateur, ce qui est vers 2008. Pas vraiment très rapide, mais. Aussi longtemps que je le sais et que je ne l'utilise pas dans du code ultra chaud.
J'aimerais l'accélérer en lançant mes propres std :: function et std :: bind, et peut-être en utilisant un tableau de tableaux plutôt qu'une unordered_map de vecteurs, mais je n'ai pas tout à fait compris comment stocker une fonction membre pointeur et appelez-le à partir d'un code qui ne sait rien de la classe appelée. La réponse de Eyelash semble très intéressante.
la source