Pourquoi C ++ n'a-t-il pas un pointeur sur le type de fonction membre?
Je pourrais être totalement faux, mais ce que je comprends, C++ n'est pas vraiment un natif de "pointeur de fonction membre". Je sais que vous pouvez faire des trucs avec Boost et mem_fun etc. Mais pourquoi les concepteurs de C++ décider de ne pas avoir une version 64 bits de pointeur contenant un pointeur vers la fonction et un pointeur vers l'objet, par exemple?
Ce que je veux dire plus précisément, c'est un pointeur vers une fonction membre d'une particulier objet de type inconnu. I. E. quelque chose que vous pouvez utiliser pour une rappel. Ce serait un type qui contient des deux valeurs. La première valeur d'un pointeur vers la fonctionet la deuxième valeur d'un pointeur vers la instance spécifique de l'objet.
Ce que je ne veux pas est un pointeur vers un général de la fonction membre d'une classe. E. G.
int (Fred::*)(char,float)
Il aurait été très utile et m'a rendu la vie plus facile.
Hugo
source d'informationauteur Rocketmagnet
Vous devez vous connecter pour publier un commentaire.
@RocketMagnet - C'est en réponse à votre autre questioncelui qui a été étiqueté comme un doublon. Je vais répondre à que question, pas celui-ci.
En général, C++ pointeur de fonctions de membre ne peut pas portably être lancé à travers la hiérarchie de classe. Cela dit, vous pouvez souvent obtenir loin avec elle. Par exemple:
Compiler ce code, et le compilateur à juste titre, se plaint:
Donc, pour répondre à "pourquoi ne pas C++ ont un pointeur-à-membres de la fonction-sur-vide-classe?", c'est que cet imaginaire de la classe de base de tout ce qui n'a pas de membres, donc il n'y a pas de valeur en toute sécurité de l'attribuer à! "void (C::)()" et "void (void::)()" sont mutuellement incompatibles types.
Maintenant, je parie que vous êtes en train de penser "attendez, j'ai jeté des états-fonction-pointeurs très bien avant!" Oui, vous avez, à l'aide de reinterpret_cast et de l'héritage simple. C'est dans la même catégorie que les autres réinterpréter jette:
Donc si
void (void::*)()
n'existe pas, mais il n'y a rien que vous puissiez en toute sécurité/portably lui attribuer.Traditionnellement, vous utilisez les fonctions de la signature
void (*)(void*)
endroit où vous souhaitez chose de l'aidevoid (void::*)()
parce que tout membre de la fonction-les pointeurs ne jette pas bien en haut et en bas de la hiérarchie d'héritage, nulle pointeurs ne exprimés ainsi. Au lieu de cela:Donc, à votre question. Pourquoi ne pas le support du C++ ce genre de casting. Pointeur-à-membres de la fonction des types de faire face à des virtuel vs non-virtuel classes de base, et virtuel vs non-virtuel fonctions de membre de, tous dans le même type, le gonflage à 4*sizeof(void*) sur certaines plates-formes. Je pense que ce serait compliquer la mise en œuvre de pointeur-à-membres de la fonction, et des matières premières des pointeurs de fonction déjà de résoudre ce problème si bien.
Comme d'autres l'ont dit, C++ donne de la bibliothèque des écrivains de suffisamment d'outils pour ce faire, et puis "normal" programmeurs comme vous et moi devrions utiliser ces bibliothèques à la place de la transpiration ces détails.
EDIT: marqué wiki de la communauté. Merci de ne modifier pour inclure des références à la norme C++, et d'ajouter en italique. (esp. ajouter des références à la norme où ma compréhension était faux! ^_^ )
Comme d'autres l'ont souligné, C++ dispose d'une fonction de membre de type pointeur.
Le terme que vous cherchez est "lié " fonction". La raison en C++ n'est pas de fournir la syntaxe de sucre pour la fonction de liaison est à cause de sa philosophie de seulement la fourniture de la plupart des outils de base, avec lequel vous pouvez ensuite construire tout ce que vous voulez. Cela permet de garder la langue "petit" (ou au moins, moins l'esprit bogglingly énorme).
De même, le C++ n'est pas un lock{} primitive comme le C#, mais il a RAII qui est utilisé par de boost scoped_lock.
Il y a bien sûr l'école de pensée qui dit que vous devez ajouter de la syntaxe de sucre pour tout ce qui pourrait être utile. Pour le meilleur ou pour le pire, C++ n'appartient pas à l'école.
Je pense que ce que vous cherchez peut-être dans ces librairies...
Rapide Délégués http://www.codeproject.com/KB/cpp/FastDelegate.aspx
Coup de pouce.Fonction http://www.boost.org/doc/libs/1_37_0/doc/html/function.html
Et voici une explication complète de pointeur de fonction des questions liées http://www.parashift.com/c++-faq-lite/pointers-to-members.html
Il n'.
Par exemple,
est un pointeur vers une fonction membre d'une classe
Fred
qui renvoie unint
et prend unchar
et unfloat
.Je pense que la réponse est que les concepteurs du C++ choisir de ne pas faire dans la langue de choses qui pourraient être facilement mis en œuvre dans une bibliothèque. Votre propre description de ce que donne une tout à fait raisonnable de façon à la mettre en œuvre.
Je sais que c'est drôle, mais le C++ est un minimaliste de la langue. Ils laissèrent à des bibliothèques de tout ce qu'ils pouvaient quitter.
TR1 a std::tr1::function, et il sera ajouté à la C++0x. Donc dans un sens il ne l'avoir.
L'une des philosophies de conception de C++ est: vous ne payez que ce que vous n'utilisez pas. Le problème avec C# style des délégués, c'est qu'ils sont lourds et nécessitent un soutien en langue, que tout le monde paie pour qu'ils les utilisent ou pas. C'est pourquoi la mise en œuvre de bibliothèque est préféré.
La raison délégués sont lourds est qu'un pointeur de méthode est souvent plus grand qu'un pointeur normal. Cela se produit chaque fois que la méthode est virtuelle. La méthode pointeur va appeler une fonction différente selon que la classe de base utilise. Qui nécessite au moins deux pointeurs, la vtable et le décalage. Il y a d'autres bizarreries impliqué avec la méthode consiste à partir d'une classe impliquée dans l'héritage multiple.
Cela dit, je ne suis pas un compilateur écrivain. Il aurait été possible de faire un nouveau type de méthode liée pointeurs qui renverserait le virtuel-ness de la méthode référencée (après tout, nous savons ce que la classe de base est de savoir si la méthode est lié).
La question est certainement pas les bases d'avoir un pointeur d'objet et d'un pointeur de fonction dans un facile à utiliser, parce que vous pouvez le faire à l'aide d'un pointeur et d'un thunk. (Ces bits sont déjà utilisés par VC++ x86 à l'appui de pointeurs vers des fonctions membre virtuelles, de sorte que ces pointeurs seulement prendre jusqu'à 4 octets.) Vous pourriez vous retrouver avec beaucoup de thunks, c'est vrai, mais les gens font déjà confiance à l'éditeur de liens pour éliminer le double modèle de instanciations -- je fais, de toute façon, et il y a une limite au nombre de vtable et cela compense, vous vous retrouverez dans la pratique. La surcharge ne serait probablement pas être important pour une taille raisonnable programme, et si vous n'utilisez pas ce genre de choses, alors il ne vous coûtera rien.
(Architectures qui, traditionnellement, l'utilisation d'une table des matières de stocker la table des matières pointeur dans la fonction pointeur de la partie, plutôt que dans le thunk, tout comme ils auraient à le faire déjà.)
(Ce nouveau type d'objet ne serait pas exactement substituables normal d'un pointeur de fonction, bien sûr, parce que la taille serait différent. Ils seraient, toutefois, être écrit de la même au point d'appel.)
Le problème que je vois est que de la convention d'appel: appuyer pointeurs vers des fonctions de cette façon pourrait être difficile dans le cas général, car le code généré aurait à préparer les arguments (ce qui inclus) de la même façon, sans égard au type réel de la chose, une fonction ou une fonction de membre à laquelle le pointeur de points.
Ce n'est probablement pas une grosse affaire sur x86, du moins pas avec thiscall, parce que vous pouvez simplement charger ECX indépendamment et acceptez que si la fonction d'appel n'en a pas besoin, puis il sera faux. (Et je pense que VC++ suppose ECX est faux dans ce cas de toute façon.) Mais sur les architectures qui passer des arguments pour les paramètres nommés dans les registres de fonctions, vous pouvez vous retrouver avec une bonne quantité de brassage dans le thunk, et si la pile des arguments sont poussés de gauche à droite, puis vous êtes essentiellement en peluche. Et cela ne peut pas être fixé de manière statique, parce que dans la limite il n'y a pas de contre-traduction-l'information de l'unité.
[Edit: MSalters, dans un commentaire à rocketmagnet du post ci-dessus, indique que si à la fois l'objet ET la fonction sont connus, alors la ce décalage, et ainsi de suite peut être déterminé immédiatement. Ce totalement n'a pas eu lieu pour moi! Mais, avec cela à l'esprit, je suppose qu'il y a seulement besoin d'être stocké l'objet précis du pointeur, peut être compensée, et la fonction exacte du pointeur. Cela rend les thunks totalement inutile, je pense, mais je suis assez sûr que les questions de pointer vers des fonctions de membre et non-membre des fonctions semblables resterait.]
C++ est déjà une grosse langue, et en ajoutant ce qui aurait fait de plus grand. Ce que vous voulez vraiment est même pire qu'un membre lié fonction, c'est quelque chose de plus proche de boost::function. Vous souhaitez stocker à la fois un
void(*)()
et une paire pour les rappels. Après tout, la raison en est que vous voulez le donner à l'appelant une complète de rappel, et le destinataire de l'appel devrait se soucient pas de l'exactitude des détails.La taille serait susceptible d'être
sizeof(void*)+sizeof(void(*)())
. Des pointeurs vers des fonctions de membre ne peut être plus grand, mais c'est parce qu'ils sont détachés. Dont ils ont besoin pour faire face à la possibilité que vous êtes à' prendre l'adresse d'une fonction virtuelle, par exemple. Toutefois, un haut-lié-pointeur-à-états-type de fonction ne souffrirait pas de cette surcharge. On peut régler la fonction exacte d'être appelé au moment de la liaison.Ce n'est pas possible avec un type défini par l'utilisateur. boost::function ne peut pas jeter la surcharge d'un PTMF lorsqu'il lie le pointeur d'objet. Vous avez besoin de savoir comprendre la structure d'un PTMF, vtable, etc ... - tous les non-norme des choses. Cependant, on peut y aller maintenant avec C++1x. Une fois qu'il est en std::, c'est juste le jeu pour les éditeurs de compilateurs. La bibliothèque standard de mise en œuvre elle-même n'est pas portable (voir, par exemple, type_info).
Vous auriez encore envie d'avoir quelques belles syntaxe, je suppose que, même si un fournisseur de compilateur met en œuvre dans la bibliothèque. J'aimerais
std::function<void(*)()> foo = &myX && X::bar
. (Il ne rentrera pas en conflit avec l'existant, de la syntaxe, comme X::le bar n'est pas une expression que &X::bar)Il me semble que les méthodes ont un implicite
this
argument, unc
pointeur sur une méthode est insuffisant pour permettre la méthode à appeler (car il n'y a aucun moyen de déterminer quelle instance doit être utilisé pourthis
(ou même si tout instance est actuellement existante)).Edit: Rocketmagnet commentaires qu'il a été abordé dans la question, et cela semble être le cas, même si je pense qu'a été ajouté après que j'ai commencé cette réponse. mais je vais dire "mea culpa", de toute façon.
Permettez-moi donc de développer la pensée un peu.
C++ est étroitement liée à c, et a tous ses types intrinsèques compatible avec les précédentes, de la langue (principalement en raison de l'histoire de
c++
développement, je suppose). Donc, un intrinsèquesc++
pointeur est unec
pointeur, et est incapable de l'appui de l'utilisation que vous demandez.Certes, vous pourriez construire un type dérivé de faire le travail---comme dans le coup de pouce de la mise en œuvre---mais tel un animal qui appartient à une bibliothèque.