16

Tener un vistazo a estas firmas de función:¿Por qué el operador de incremento postfix toma un parámetro ficticio?

class Number { 
public: 
    Number& operator++(); // prefix ++ 
    Number operator++ (int); // postfix ++ 
}; 

Prefijo no toma ningún parámetro postfijo pero lo hace. ¿Por qué? Pensé que podemos reconocerlos con diferentes tipos de devolución.

+0

Las * solo * sobrecargas de tiempo C++ por tipo de retorno son para el operador de tipo de cambio. –

+0

@Mike: no creo que la resolución de sobrecarga entre en juego en ese caso. –

+0

Buen punto. Siempre lo he pensado como "sobrecargar al operador de tipografía", pero tal vez haya un término mejor. –

Respuesta

8

Usted es libre de dar operador ++ cualquier tipo de devolución que desee, por lo que no hay manera de distinguir postfijo y prefijo por eso. Entonces el compilador necesita algún tipo de pista.

otoh, no sé por qué esto no podía se había hecho en única sintaxis:

//prefix 
int& ++operator(); 
//postfix 
int& operator++(); 

Después de todo, imitando el uso de declaraciones tiene tradición en C y C++.

P.S. Otros carteles: esto no tiene nada que ver con la sobrecarga por tipo de devolución. postfix y el prefijo ++/- son dos nombres diferentes. No es necesario resolver una sobrecarga en x++ o ++x, porque está completamente claro qué nombre significa.

+0

es, podría ser que podrían haberlo hecho de la manera en que sugirió :) .. tan solo para la diferenciación del compilador escriben el parámetro ¿verdad? otra Pregunta, ¿por qué hicieron postfix para aceptar el parámetro, ¿por qué no prefijo? podrían haberse intercambiado bien, ¿alguna diferencia específica? – Naruto

+0

Eso probablemente habría requerido concesiones especiales en la gramática, que ya es casi tan compleja como viene. Además, el siguiente paso lógico sería hacer que los otros operadores unarios coincidan con la notación de prefijo/postfijo para coherencia. En ese caso, ¿qué significaría 'T & operator()'? –

+2

@Shadow: el parámetro adicional para postfix funciona como un recordatorio visual de que la acción ocurre en el lado derecho. –

2

No está permitido sobrecargar funciones puramente por tipo de devolución, por lo que es necesario un parámetro ficticio para diferenciar entre dos operadores de aspecto idéntico operator++().

7

Prefijo y postfix ++ son operadores diferentes. Con la declaración de estilo estándar Foo operator symbol(Foo &), no había una manera obvia de distinguir los dos. En lugar de presentar una nueva sintaxis como Foo symbol operator(Foo &) que lo convertiría en un caso especial a diferencia de todos los demás operadores y probablemente un poco doloroso de analizar, los diseñadores de idiomas querían alguna otra solución.

La solución que eligieron era un tanto extraña. Observaron que todos los demás operadores 'postfix' (es decir, operadores que ocurrieron después de uno de sus operandos) eran en realidad operadores infija que tomaban dos argumentos. Por ejemplo, simple viejo + o -. Sobre esta base, los diseñadores del lenguaje decidieron que tener un argumento ficticio aleatorio sería una buena forma de distinguir entre el prefijo y el postfijo ++.

En mi humilde opinión, es una de las decisiones más extrañas tomadas a medida que C++ evolucionó. Pero ahí lo tienes.

Y no puede distinguirlos según el tipo de devolución por dos razones.

La primera es que las funciones en C++ no se pueden sobrecargar en el tipo de devolución. No puede tener dos funciones que tengan nombres idénticos y listas de tipos de parámetros pero diferentes valores de retorno.

El segundo es que el método no sería lo suficientemente robusto o flexible como para manejar todas las posibles implementaciones de prefijo y postfix ++.

Por ejemplo, puede querer un postfijo ++ que devolvió un tipo de referencia si la única razón por la que lo llamó fue para invocar un efecto secundario no relacionado con el valor de la variable a la que lo estaba aplicando. En mi opinión, esa sería una implementación muy mala, pero C++ no se trata de juzgar qué tipo de código estúpido quieres escribir, sino de permitirte escribir el código que consideres apropiado para la situación. Y forzarle a usar un estilo particular de tipo de devolución para el prefijo ++ y postfix ++ sería contrario a ese espíritu.

+3

Como nota al margen, obtuve esta información de "El diseño y la evolución de C++" de Bjarne Stroustroup. Lo recomendaría si realmente quieres entender por qué C++ es la forma en que es. Hacer crecer un idioma mediante la acreción en un entorno donde la compatibilidad con versiones anteriores es muy importante genera muchas cosas extrañas. – Omnifarious

+0

No hay ninguna alternativa realmente buena, sin embargo. Podría inventar un pseudooperador (por ejemplo, 'operator +++') que la gente olvidará o equivocar, o agregar una palabra clave (por ejemplo 'post operator ++'), o abandonar usando los operadores mismos y usar nombres especiales en su lugar (por ejemplo, '__add__' de Python y amigos). Todos parecen peores que la variable ficticia. –

+0

Sí, 'operator post_increment' sería mucho más fácil de leer, pero luego' post_increment' se convierte en una palabra reservada, posiblemente rompiendo compiladores u otros programas que ya usan ese nombre. Por lo tanto, la convención de "nombres con guiones bajos principales de Python está reservada". Consulte la historia de XHTML para ver un ejemplo de por qué no causar una rotura masiva de compatibilidad con versiones anteriores en un nuevo estándar. –

6

directamente de la boca Bjarne:

Esto puede ser a la vez demasiado lindo y demasiado sutil, pero funciona, no requiere nueva sintaxis, y tiene una lógica en la locura. Otros operadores unarios son prefijo y no toman argumentos cuando se definen como funciones miembro. El argumento int "dummy" y dummy sin usar se usa para indicar los operadores impares del sufijo. En otras palabras, en el caso de postfix, ++ viene entre el primer operando (real) y el segundo argumento (ficticio) y es, por lo tanto, postfijo.

Estas explicaciones son necesarias porque el mecanismo es único y, por lo tanto, es un poco verrugoso. Dada una elección, probablemente habría introducido las palabras clave prefix y postfix, pero eso no parecía factible en ese momento. Sin embargo, el único punto realmente importante es que el mecanismo funciona y puede ser entendido y utilizado por los pocos programadores que realmente lo necesitan.

Por cierto, en mi opinión, sólo el prefijo ++ debería ser sobrecargable por el programador, y Postfix ++ debería generarse automáticamente por el compilador. ¿Alguien esta de acuerdo conmigo?

+0

¿Alguien está de acuerdo conmigo? - '#include ' – UncleBens

+0

No es la forma en que el idioma está configurado actualmente, no. Creo que sería genial si, después de 0x, pudiésemos habilitar operadores por defecto y dejar que el compilador los construya a partir de otros operadores que usted defina. –

+0

http://www.stroustrup.com/dne.html –

0

Si tuviera mi druthers, postincrement y muchos operadores de punto de secuencia se dividirían en dos o tres partes; en el caso de postincremento, una declaración como "a = (b ++ + C++);" se traduciría efectivamente como "a = postinc1 (b) + postinc1 (c); postinc2 (b); postinc2 (c);"; la segunda parte del incremento posterior sería una función vacía. En la implementación real, las llamadas postinc2() probablemente ocurran con frecuencia mientras que otros resultados están en la pila de evaluación; eso no debería ser demasiado difícil de implementar para un compilador.

En el caso de "& &" o "||", la primera parte del operador solo operaría en el operando izquierdo; si devuelve un valor distinto de cero (para & &) o no es cero (para ||), la segunda parte funcionará en ambos operandos.

En el caso de "?"/":", La primera parte del operador funcionaría solo en el primer operando. Si devuelve un valor distinto de cero, la segunda parte operaría en los parámetros primero y segundo; de lo contrario, la tercera parte operaría en los parámetros primero y tercero.

¿Hay algún idioma que haga algo como eso? Parece extraño que C++ permita que los operadores se redefinan de manera que rompa el comportamiento de la secuencia, pero no permite que se redefinan de forma que se conserven.

0

El compilador utiliza el argumento int para distinguir entre los operadores de incremento de prefijo y postfijo. Para llamadas implícitas, el valor predeterminado es cero por lo que en realidad no hace tanta diferencia en la funcionalidad del operador sobrecargado ...

Cuestiones relacionadas