2010-02-28 14 views
21

Recientemente he descubierto que en C++ se puede sobrecargar el operador de "llamada a la función", de una manera extraña en la que usted tiene que escribir dos pares de paréntesis para hacerlo:¿Cómo puede ser útil sobrecargar el operador de "llamada de función"?

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

Y luego usarlo de esta manera:

A a; 
a(); 

¿Cuándo es útil?

+3

Lea sobre objetos funcionales. http://en.wikipedia.org/wiki/Function_object – AnT

Respuesta

27

Esto puede ser usado para crear "functors", objetos que actúan como funciones:

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; 

Las impresiones anteriores 20. El artículo de Wikipedia vinculado anteriormente ofrece ejemplos más sustanciales.

+3

Y la razón principal por la que querrías funtores es tener funciones de orden superior en C++. –

+1

Puede expandir esto para, por ejemplo, multiplicar por m la primera vez que lo llame, multiplicar por m + 1 la segunda vez, etc. Las funciones normales no pueden guardar ninguna información de estado entre llamadas, pero los funtores pueden hacerlo. – MatrixFrog

+3

Bueno, siempre puede usar variables estáticas en una función para darle el estado (o globales - estremecimiento). Pero ambos son muy feos y propensos a errores. (Usaría un functor en su lugar ... pero es posible) –

1

Si está realizando una clase que encapsula un puntero de función, esto podría hacer que el uso sea más obvio.

4

Un algoritmo implementado utilizando una plantilla no le importa si la cosa que se llama es una función o un funtor, se preocupa por la sintaxis. O bien los estándares (por ejemplo, for_each()) o los tuyos. Y los funtores pueden tener estado y hacer todo tipo de cosas cuando se les llama. Las funciones solo pueden tener estado con una variable local estática o variables globales.

15

Hay poco más que una ganancia sintáctica en el uso del operador() hasta que empiece a usar plantillas. Pero cuando se usan plantillas, se pueden tratar funciones reales y funtores (clases que actúan como funciones) de la misma manera.

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

Sí; los objetos parecidos a funciones realmente son más útiles cuando tienes un tipado suficientemente débil. C++ no tiene eso, pero las plantillas sí. –

+0

Typo en el constructor scaled_sine, creo. –

0

El compilador también puede alinear el functor y la llamada de función. Sin embargo, no puede alinear un puntero a la función. De esta forma, el uso del operador de llamada a función puede mejorar significativamente el rendimiento cuando se utiliza, por ejemplo, con los algoritmos de biblioteca estándar de C++.

Cuestiones relacionadas