En programación de computadoras , la sobrecarga de operadores , a veces denominada polimorfismo ad hoc de operador , es un caso específico de polimorfismo , donde diferentes operadores tienen diferentes implementaciones dependiendo de sus argumentos. La sobrecarga de operadores generalmente está definida por un lenguaje de programación , un programador o ambos.
La sobrecarga de operadores es azúcar sintáctica y se utiliza porque permite programar usando notación más cercana al dominio de destino [1] y permite a los tipos definidos por el usuario un nivel similar de soporte sintáctico al de los tipos integrados en un lenguaje. Es común, por ejemplo, en informática científica, donde permite manipular representaciones informáticas de objetos matemáticos con la misma sintaxis que en papel.
La sobrecarga de operadores no cambia el poder expresivo de un lenguaje (con funciones), ya que se puede emular mediante llamadas a funciones. Por ejemplo, considere variables a
y b
de c
algún tipo definido por el usuario, como matrices :
a + b * c
En un lenguaje que admite la sobrecarga de operadores, y con la suposición habitual de que el operador '*' tiene mayor prioridad que el operador '+', esta es una forma concisa de escribir:
Add(a, Multiply(b, c))
Sin embargo, la sintaxis anterior refleja un uso matemático común.
En este caso, el operador de suma está sobrecargado para permitir la suma en un tipo definido por el usuario Time
en C++ :
Operador de tiempo + ( Tiempo constante & lhs , Tiempo const & rhs ) { Tiempo temp = lhs ; temperatura . segundos += derecho . segundos ; temperatura . minutos += temperatura . segundos / 60 ; temperatura . segundos %= 60 ; temperatura . minutos += derecha . minutos ; temperatura . horas += temp . minutos / 60 ; temperatura . minutos %= 60 ; temperatura . horas += derecha . horas ; temperatura de retorno ; }
La suma es una operación binaria , lo que significa que tiene dos operandos . En C++, los argumentos que se pasan son los operandos y el temp
objeto es el valor devuelto.
La operación también podría definirse como un método de clase, reemplazándolo por el argumento lhs
oculto ; this
Sin embargo, esto obliga al operando izquierdo a ser del tipo Time
:
// La "const" justo antes de la llave de apertura significa que |this| no se modifica. Tiempo Tiempo :: operador + ( const Tiempo & rhs ) const { Tiempo temp = * this ; // |esto| No debe modificarse, así que haga una copia. temperatura . segundos += derecho . segundos ; temperatura . minutos += temperatura . segundos / 60 ; temperatura . segundos %= 60 ; temperatura . minutos += derecha . minutos ; temperatura . horas += temp . minutos / 60 ; temperatura . minutos %= 60 ; temperatura . horas += derecha . horas ; temperatura de retorno ; }
Tenga en cuenta que un operador unario definido como método de clase no recibiría ningún argumento aparente (solo funciona desde this
):
bool Hora :: operador ! () const { horas de retorno == 0 && minutos == 0 && segundos == 0 ; }
El operador menor que (<) suele estar sobrecargado para ordenar una estructura o clase:
clase Par { público : operador bool < ( const Par & p ) const { if ( x_ == p . x_ ) { return y_ < p . y_ ; } devolver x_ < p . X_ ; } privado : int x_ ; int y_ ; };
Al igual que en los ejemplos anteriores, en el último ejemplo la sobrecarga de operadores se realiza dentro de la clase. En C++, después de sobrecargar el operador menor que (<), se pueden usar funciones de clasificación estándar para ordenar algunas clases.
La sobrecarga de operadores ha sido criticada a menudo [2] porque permite a los programadores reasignar la semántica de los operadores dependiendo de los tipos de sus operandos. Por ejemplo, el uso del <<
operador en C++ desplaza los bits de la variable a la izquierda en bits si y son de tipo entero, pero si es un flujo de salida, entonces el código anterior intentará escribir a en el flujo. Debido a que la sobrecarga de operadores permite al programador original cambiar la semántica habitual de un operador y tomar por sorpresa a los programadores posteriores, se considera una buena práctica utilizar la sobrecarga de operadores con cuidado (los creadores de Java decidieron no utilizar esta característica, [3] aunque no necesariamente por este motivo).a << b
a
b
a
b
a
b
Otro problema, más sutil, con los operadores es que ciertas reglas de las matemáticas pueden esperarse erróneamente o asumirse involuntariamente. Por ejemplo, la conmutatividad de + (es decir, que a + b == b + a
) no siempre se aplica; un ejemplo de esto ocurre cuando los operandos son cadenas, ya que + comúnmente se sobrecarga para realizar una concatenación de cadenas (es decir, "bird" + "song"
produce "birdsong"
, mientras que "song" + "bird"
produce "songbird"
). Una respuesta típica [ cita necesaria ] a este argumento proviene directamente de las matemáticas: si bien + es conmutativo en números enteros (y, más generalmente, en cualquier número complejo), no es conmutativo para otros "tipos" de variables. En la práctica, + ni siquiera siempre es asociativo , por ejemplo con valores de coma flotante debido a errores de redondeo. Otro ejemplo: en matemáticas, la multiplicación es conmutativa para números reales y complejos pero no conmutativa en la multiplicación de matrices .
Se realiza una clasificación de algunos lenguajes de programación comunes según si sus operadores son sobrecargables por parte del programador y si los operadores están limitados a un conjunto predefinido.
La especificación ALGOL 68 permitía la sobrecarga del operador. [44]
Extracto de la especificación del lenguaje ALGOL 68 (página 177) donde se definen los operadores sobrecargados ¬, =, ≠ y abs :
10.2.2. Operaciones con operandos booleanosa) op ∨ = ( bool a, b) bool :( a | verdadero | b );b) op ∧ = ( bool a, b) bool : ( a | b | falso );c) op ¬ = ( bool a ) bool : ( a | falso | verdadero );d) op = = ( bool a, b) bool :( a∧b ) ∨ ( ¬b∧¬a );e) op ≠ = ( bool a, b) bool : ¬(a=b);f) op abs = ( bool a ) int : ( a | 1 | 0 );
Tenga en cuenta que no se necesita ninguna declaración especial para sobrecargar un operador y el programador es libre de crear nuevos operadores. Para los operadores diádicos se puede establecer su prioridad en comparación con otros operadores:
prio máx = 9; op máx = ( int a, b) int : ( a>b | a | b ); op ++ = ( ref int a ) int : ( a +:= 1 );
Ada soporta la sobrecarga de operadores desde sus inicios, con la publicación del estándar de lenguaje Ada 83. Sin embargo, los diseñadores del lenguaje optaron por excluir la definición de nuevos operadores. Sólo se pueden sobrecargar los operadores existentes en el lenguaje, definiendo nuevas funciones con identificadores como "+", "*", "&", etc. Las revisiones posteriores del lenguaje (en 1995 y 2005) mantienen la restricción a la sobrecarga de los operadores existentes. .
En C++ , la sobrecarga de operadores es más refinada que en ALGOL 68 . [45]
Los diseñadores del lenguaje Java de Sun Microsystems optaron por omitir la sobrecarga. [46] [47] [48]
Python permite la sobrecarga de operadores mediante la implementación de métodos con nombres especiales. [49] Por ejemplo, el operador de suma (+) se puede sobrecargar implementando el método obj.__add__(self, other)
.
Ruby permite la sobrecarga de operadores como azúcar sintáctico para llamadas a métodos simples.
Lua permite la sobrecarga de operadores como azúcar sintáctico para llamadas a métodos con la característica adicional de que si el primer operando no define ese operador, se usará el método para el segundo operando.
Microsoft agregó la sobrecarga de operadores a C# en 2001 y a Visual Basic .NET en 2003.
Scala trata a todos los operadores como métodos y, por lo tanto, permite la sobrecarga de operadores mediante proxy.
En Raku , la definición de todos los operadores se delega a funciones léxicas y, por lo tanto, utilizando definiciones de funciones, se pueden sobrecargar operadores o agregar nuevos operadores. Por ejemplo, la función definida en la fuente de Rakudo para incrementar un objeto Fecha con "+" es:
infijo múltiple :<+> ( Fecha:D $d , Int:D $x ) { Fecha . nuevo desde el recuento diario ( $d . recuento diario + $x )}
Dado que se usó "multi", la función se agrega a la lista de candidatos de envío múltiple y "+" solo se sobrecarga en el caso en que se cumplan las restricciones de tipo en la firma de la función. Si bien la capacidad de sobrecarga incluye + , * , >= , el sufijo y el término i , etc., también permite sobrecargar varios operadores de llaves: " [ x, y ] ", "x [ y ] ", "x { y } ", y "x ( y ) ".
Kotlin ha soportado la sobrecarga de operadores desde su creación.
{{cite web}}
: Comprobar |url=
valor ( ayuda )Una de las características más interesantes de la programación orientada a objetos de C++ es que puede sobrecargar operadores para manejar objetos de sus clases (no puede hacer esto en otros lenguajes centrados en la programación orientada a objetos, como Java).