c++ - una - ¿Por qué el operador de incremento de postfix toma un parámetro ficticio?
operador++ en c (6)
Directamente de la boca de Bjarne:
Esto puede ser demasiado lindo y demasiado sutil, pero funciona, no requiere una nueva sintaxis y tiene una lógica a la locura. Otros operadores unarios son prefijo y no toman argumentos cuando se definen como funciones miembro. El argumento "impar" y el dummy
int
utilizado se utiliza para indicar los operadores de postfix impares. En otras palabras, en el caso de postfix,++
interpone entre el primer operando (real) y el segundo argumento (ficticio) y, por lo tanto, es postfix.Estas explicaciones son necesarias porque el mecanismo es único y por lo tanto un poco de una verruga. Dada la opción, probablemente hubiera introducido el
prefix
y las palabras clavepostfix
, pero eso no parecía factible en ese momento. Sin embargo, el único punto realmente importante es que el mecanismo funciona y puede ser comprendido y utilizado por los pocos programadores que realmente lo necesitan.
Por cierto, en mi opinión, solo el prefijo ++
debe ser sobrecargado por el programador, y postfix ++
debe ser generado automáticamente por el compilador. ¿Alguien esta de acuerdo conmigo?
Echa un vistazo a estas firmas de funciones:
class Number {
public:
Number& operator++ (); // prefix ++
Number operator++ (int); // postfix ++
};
Prefijo no toma ningún parámetro pero postfix lo hace. ¿Por qué? Pensé que podemos reconocerlos con diferentes tipos de retorno.
El compilador utiliza el argumento int para distinguir entre los operadores de incremento de prefijo y postfijo. Para las llamadas implícitas, el valor predeterminado es cero, por lo que no hace mucha diferencia en la funcionalidad del operador sobrecargado ...
No está permitido sobrecargar las funciones únicamente por tipo de retorno, por lo que es necesario un parámetro ficticio para diferenciar entre dos operator++()
aspecto idéntico.
Prefijo y postfix ++
son diferentes operadores. Con la declaración de estilo del Foo operator symbol(Foo &)
no había una forma obvia de distinguirlos. En lugar de crear una nueva sintaxis como el Foo symbol operator(Foo &)
que lo convertiría en un caso especial, a diferencia de todos los demás operadores y probablemente un poco difícil de analizar, los diseñadores de idiomas querían alguna otra solución.
La solución que eligieron fue algo extraña. Notaron que todos los otros operadores ''postfix'' (es decir, los operadores que ocurrieron después de uno de sus operandos) eran en realidad operadores de infijo que tomaron dos argumentos. Por ejemplo, llano antiguo +
, /
o >
. Sobre esta base, los diseñadores de lenguaje decidieron que tener un argumento ficticio aleatorio sería una buena manera de distinguir entre prefijo y postfix ++
.
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 retorno. No puede tener dos funciones que tengan nombres idénticos y listas de tipos de parámetros pero valores de retorno diferentes.
La segunda es que el método no sería lo suficientemente robusto o flexible para manejar todas las implementaciones posibles de prefix y postfix ++
.
Por ejemplo, es posible que desee un postfix ++
que devuelva 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é tipos de código estúpido quieres escribir, sino de permitirte escribir cualquier código que creas apropiado para la situación. Y forzarlo a usar un estilo particular de tipo de retorno para el prefijo ++
y postfix ++
sería contrario a ese espíritu.
Si tuviera mis druthers, el postincremento y muchos operadores de puntos 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 post-incremento sería una función nula. En la implementación real, las llamadas postinc2 () a menudo deberían ocurrir mientras que otros resultados se encuentran 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 devolviera un valor distinto de cero (para &&) o distinto de cero (para ||), entonces la segunda parte operaría en ambos operandos.
En el caso de "?" / ":", La primera parte del operador operaría solo en el primer operando. Si volviera a ser diferente a cero, la segunda parte operaría en el primer y segundo parámetro; De lo contrario, la tercera parte operaría en el primer y tercer parámetro.
¿Algún idioma hace algo así? Parece extraño que C ++ permita que los operadores se redefinan de manera que rompan el comportamiento de secuenciación, pero no les permite ser redefinidos de manera que lo preserven.
Usted es libre de dar al operador ++ el tipo de devolución que desee, por lo que no hay manera de distinguir entre prefijo y prefijo. Así que el compilador necesita algún tipo de pista.
OTOH, no sé por qué no se pudo haber hecho esto solo en sintaxis:
//prefix
int& ++operator ();
//postfix
int& operator++ ();
Después de todo, la imitación del uso en declaraciones tiene tradición en C y C ++.
PS Otros carteles: Esto no tiene nada que ver con la sobrecarga por tipo de devolución. Postfix y prefijo ++ / - son dos nombres diferentes. No es necesario resolver una sobrecarga en x++
o ++x
, porque está completamente claro a qué nombre se refiere.