2010-02-28 25 views
21

J'ai récemment découvert que, en C++, vous pouvez surcharger l'opérateur « fonction d'appel », d'une manière étrange dans laquelle vous devez écrire deux paires de parenthèses pour le faire:Comment peut-il être utile de surcharger l'opérateur "appel de fonction"?

class A { 
    int n; 
public: 
    void operator()() const; 
}; 

Et puis utilisez cette façon:

A a; 
a(); 

Quand est-ce utile?

+3

En savoir plus sur les objets de fonction. http://en.wikipedia.org/wiki/Function_object – AnT

Répondre

27

Ceci peut être utilisé pour créer "functors", des objets qui agissent comme des fonctions:

class Multiplier { 
public: 
    Multiplier(int m): multiplier(m) {} 
    int operator()(int x) { return multiplier * x; } 
private: 
    int multiplier; 
}; 

Multiplier m(5); 
cout << m(4) << endl; 

Les impressions ci-dessus 20. L'article Wikipedia ci-dessus donne des exemples plus substantiels.

+3

Et la principale raison pour laquelle vous voudriez des foncteurs est d'avoir des fonctions d'ordre supérieur en C++. –

+1

Vous pouvez l'étendre pour, par exemple, multiplier par m la première fois que vous l'appelez, multiplier par m + 1 la deuxième fois, etc. Les fonctions normales ne peuvent pas enregistrer d'informations d'état entre les appels, mais les foncteurs peuvent le faire. – MatrixFrog

+3

Eh bien, vous pouvez toujours utiliser des variables statiques dans une fonction pour lui donner l'état (ou globals - shudder). Mais les deux sont très laids et sujettes aux erreurs. (J'utiliserais un foncteur à la place .. mais c'est possible) –

1

Si vous créez une classe qui encapsule un pointeur de fonction, cela peut rendre l'utilisation plus évidente.

4

Un algorithme implémenté à l'aide d'un modèle ne se soucie pas que la chose appelée soit une fonction ou un foncteur, elle se soucie de la syntaxe. Les uns standard (par exemple for_each()) ou les vôtres. Et les foncteurs peuvent avoir un état et faire toutes sortes de choses quand ils sont appelés. Les fonctions peuvent uniquement avoir un état avec une variable locale statique ou des variables globales.

15

Il n'y a guère plus qu'un gain syntaxique à utiliser operator() jusqu'à ce que vous commenciez à utiliser des templates. Mais lorsque vous utilisez des modèles, vous pouvez traiter les fonctions réelles et les foncteurs (classes agissant comme des fonctions) de la même manière.

class scaled_sine 
{ 
    explicit scaled_sine(float _m) : m(_m) {} 
    float operator()(float x) const { return sin(m*x); } 
    float m; 
}; 

template<typename T> 
float evaluate_at(float x, const T& fn) 
{ 
    return fn(x); 
} 

evaluate_at(1.0, cos); 
evaluate_at(1.0, scaled_sine(3.0)); 
+0

Yep; Les objets fonctionnels sont vraiment utiles lorsque vous avez une saisie suffisamment faible. C++ n'a pas cela, mais les templates le font. –

+0

Typo dans le constructeur scaled_sine je pense. –

0

Le compilateur peut également intégrer le foncteur et l'appel de fonction. Cependant, il ne peut pas intégrer un pointeur de fonction. De cette façon, l'utilisation de l'opérateur d'appel de fonction peut améliorer considérablement les performances lorsqu'il est utilisé par exemple avec les algorithmes de librairie C++ standard.