229 votes

Pourquoi toutes ces définitions de pointeur de fonction fou tout le travail ? Ce qui se passe réellement ?

Tout en travaillant mon chemin à travers Le Langage de Programmation C++ (TCPL), je me suis retrouvé à la mise en œuvre du programme de calcul dans le Chapitre 6. Le débogage de mon code, j'ai remarqué que j'avais tapé get_token; au lieu de get_token();. Avec l'erreur, le programme compilé, mais il n'a rien fait. Solution facile.

Cela m'a fait penser à ce que le nom d'une fonction. J'ai été à essayer de comprendre où vous n'auriez jamais utiliser simplement le nom de la fonction, sans l' () de l'opérateur. Puis il est venu à moi, pointeur de fonction définitions!

Malheureusement, comme je l'ai joué un peu avec ce que j'ai une fois de rappeler à propos des pointeurs de fonction, j'ai trouvé que je pouvais pas bien comprendre ce qui se passait.

Voici ce que j'ai été jouer avec:

void foo() {
    cout << "Foo to you too!\n";
};

int main() {
    void (*p1_foo)() = foo;
    void (*p2_foo)() = *foo;
    void (*p3_foo)() = &foo;
    void (*p4_foo)() = *&foo;
    void (*p5_foo)() = &*foo;
    void (*p6_foo)() = **foo;
    void (*p7_foo)() = **********************foo;

    (*p1_foo)();
    (*p2_foo)();
    (*p3_foo)();
    (*p4_foo)();
    (*p5_foo)();
    (*p6_foo)();
    (*p7_foo)();

La partie folle (pour moi en tout cas!) c'est que tous les sept pointeurs travaillé et réussi a appelé la fonction, de l'imprimerie Foo to you too!... en Effet!!

Donc ce qui se passe réellement ici?

233voto

James McNellis Points 193607

Il ya quelques morceaux de ce qui permet à tous de ces combinaisons d'opérateurs de travailler de la même façon.

La raison fondamentale de l'ensemble de ces travaux est qu'une fonction (comme foo) est implicitement converti en un pointeur vers la fonction. C'est pourquoi, void (*p1_foo)() = foo; fonctionne: foo est implicitement converti en un pointeur à lui-même et que le pointeur est affecté p1_foo.

Unaire &, lorsqu'il est appliqué à une fonction renvoie un pointeur vers la fonction, tout comme il donne l'adresse d'un objet lorsqu'il est appliqué à un objet. Pour les pointeurs de fonctions ordinaires, il est toujours redondante, car de l'implicite de la fonction à la fonction de pointeur de la conversion. En tout cas, c'est pourquoi, void (*p3_foo)() = &foo; travaux.

Unaire *, lorsqu'il est appliqué à un pointeur de fonction, les rendements de la pointe-à la fonction, tout comme il donne de la pointe-à l'objet lorsqu'il est appliqué à un simple pointeur vers un objet.

Ces règles peuvent être combinés. Considérez votre avant-dernier exemple, **foo:

  • Tout d'abord, foo est implicitement converti en un pointeur sur lui-même et le premier * est appliquée à la fonction de pointeur, rendement de la fonction foo de nouveau.
  • Ensuite, le résultat est à nouveau implicitement converti en un pointeur sur lui-même et le second * est appliqué, encore une fois céder la fonction foo.
  • Il est alors implicitement converti en un pointeur de fonction à nouveau et affectée à la variable.

Vous pouvez ajouter autant d' *s que vous le souhaitez, le résultat est toujours le même. Les plus *s, plus on rit.

On peut aussi considérer votre cinquième exemple, &*foo:

  • Tout d'abord, foo est implicitement converti en un pointeur sur lui-même; unaire * est appliqué, rendement foo de nouveau.
  • Ensuite, l' & est appliqué à l' foo, ce qui donne un pointeur vers foo, ce qui est affectée à la variable.

L' & ne peut être appliqué à une fonction, et non à une fonction qui a été converti en un pointeur de fonction (à moins, bien sûr, la fonction de pointeur est une variable, auquel cas le résultat est un pointeur vers un pointeur à une fonction; par exemple, vous pourriez ajouter à votre liste void (**pp_foo)() = &p7_foo;).

C'est pourquoi, &&foo ne fonctionne pas: &foo n'est pas une fonction, c'est un pointeur de fonction qui est une rvalue. Toutefois, &*&*&*&*&*&*foo , comme le ferait &******&foo, parce que dans ces deux expressions de l' & est toujours appliqué à une fonction et non pas à une rvalue pointeur de fonction.

Notez également que vous n'avez pas besoin d'utiliser le unaire * de faire l'appel via le pointeur de fonction; les deux (*p1_foo)(); et (p1_foo)(); ont le même résultat, à nouveau en raison de la fonction à la fonction de pointeur de la conversion.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X