Sobrecarga de operadores

Compartir Imprimir Citar
Características de algunos idiomas de programación

En la programación informática, la sobrecarga de operadores, a veces denominada polimorfismo ad hoc del operador, es un caso específico de polimorfismo, en el que diferentes operadores tienen diferentes implementaciones según sus argumentos. La sobrecarga de operadores generalmente se define por un lenguaje de programación, un programador o ambos.

Razón

La sobrecarga de operadores es azúcar sintáctica y se usa porque permite programar usando notación más cercana al dominio de destino y permite que los tipos definidos por el usuario tengan un nivel similar de compatibilidad sintáctica como los tipos integrados en un lenguaje. Es habitual, por ejemplo, en la 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 usando llamadas a funciones. Por ejemplo, considere las variables a, b y c de algún tipo definido por el usuario, como matrices:

a + b * c

En un lenguaje que admita la sobrecarga de operadores y con la suposición habitual de que el '*' el operador tiene mayor precedencia que el '+' operador, esta es una forma concisa de escribir:

Añadir(a, Multiplicar(b, c))

Sin embargo, la sintaxis anterior refleja el uso matemático común.

Ejemplos

En este caso, el operador de adición está sobrecargado para permitir la adición en un tipo definido por el usuario Tiempo en C++:

Hora operador+()const Hora" #, const Hora" rhs) {} Hora tempestad = #; tempestad.segundos += rhs.segundos; tempestad.minutos += tempestad.segundos / 60; tempestad.segundos %= 60; tempestad.minutos += rhs.minutos; tempestad.horas += tempestad.minutos / 60; tempestad.minutos %= 60; tempestad.horas += rhs.horas; retorno tempestad;}

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, reemplazando lhs por el argumento oculto este; Sin embargo, esto fuerza que el operando izquierdo sea del tipo Time:

// El "const" justo antes de la apertura curly brace significa que TENESTA SUPERVISIÓN no es modificado.Hora Hora::operador+()const Hora" rhs) const {} Hora tempestad = *esto; // Silencioesta vida no debe ser modificada, así que haga una copia. tempestad.segundos += rhs.segundos; tempestad.minutos += tempestad.segundos / 60; tempestad.segundos %= 60; tempestad.minutos += rhs.minutos; tempestad.horas += tempestad.minutos / 60; tempestad.minutos %= 60; tempestad.horas += rhs.horas; retorno tempestad;}

Tenga en cuenta que un operador unario definido como un método de clase no recibiría ningún argumento aparente (solo funciona desde este):

bool Hora::operador!() const {} retorno horas == 0 " minutos == 0 " segundos == 0;}

El operador menor que (<) a menudo se sobrecarga para ordenar una estructura o clase:

clase Pareja {} público: bool operador.()const Pareja" p) const {} si ()x_ == p.x_) {} retorno Y... . p.Y...; } retorno x_ . p.x_; } privado: int x_; int Y...;};

Al igual que con 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 (<), las funciones de ordenación estándar se pueden usar para ordenar algunas clases.

Críticas

La sobrecarga de operadores a menudo ha sido criticada porque permite a los programadores reasignar la semántica de los operadores según los tipos de sus operandos. Por ejemplo, el uso de << operador en C++ a << b cambia los bits en la variable a dejado por b bits si a y b son de tipo entero, pero si a es un flujo de salida, luego el código anterior intentará escribir un b en la transmisión. Debido a que la sobrecarga de operadores permite al programador original cambiar la semántica habitual de un operador y sorprender a los programadores posteriores, se considera una buena práctica usar la sobrecarga de operadores con cuidado (los creadores de Java decidieron no usar esta función, aunque no necesariamente por esta razón).

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 + se suele sobrecargar para realizar una concatenación de cadenas (es decir, "pájaro" + "canción" produce "canto de pájaro", mientras que "canción" + "pájaro" produce "songbird"). Un contraataque típico a este argumento proviene directamente de las matemáticas: mientras que + 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 es siempre asociativo, por ejemplo, con valores de punto 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.

Catálogo

Se hace una clasificación de algunos lenguajes de programación comunes según si sus operadores son sobrecargables por el programador y si los operadores están limitados a un conjunto predefinido.

Operadores No sobrecargable Sobrecargable
Nuevo definible
  • ML
  • Pico
  • Prolog
  • Smalltalk
  • ALGOL 68
  • Clojure
  • Eiffel
  • Fortran
  • Futhark
  • F#
  • Haskell
  • Io
  • Nim
  • R
  • Raku
  • Scala
  • Semillas7
  • Swift
Set limitado
  • BASIC
  • C
  • Vamos.
  • Java
  • JavaScript
  • Modula-2
  • Objetivo-C
  • Pascal
  • TipoScript
  • Visual Basic
  • Ada
  • C#
  • C++
  • Ceylon
  • D
  • Dart
  • FreeBASIC
  • Groovy
  • Java
  • Kotlin
  • Lua
  • MATLAB
  • Object Pascal (Free Pascal, Delphi (desde 2005))
  • PHP (utilizando métodos mágicos, interfaz ArrayAccess, o extensión Operator)
  • Perl
  • Python
  • Ruby
  • Rust
  • Visual Basic.NET

Cronología de la sobrecarga de operadores

Década de 1960

La especificación ALGOL 68 permitía la sobrecarga de operadores.

Extracto de la especificación del lenguaje ALGOL 68 (página 177) donde se definen los operadores sobrecargados ¬, =, ≠ y abs:

10.2.2. Operaciones en Óperas Booleanas
a) operaciones latitud =bool a, b) bool: verdadero.
b) operaciones ∧ =bool a, b) bool: (a Silencio b Silencio falso);
c) operaciones ¬ =bool a) bool(a Silencio falso Silencio verdadero);
d) operaciones = = = =bool a, b) bool:(a∧b) ∨ (¬b∧¬a);
e) operaciones ل =bool a, b) bool¬(a=b);
f) operaciones abdominales =bool a)int: (a TENCIÓN 1 TENIDO 0);

Tenga en cuenta que no se necesita una 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 max = 9;

 operaciones max =int a, b) int: (a saber: " preservar ")
 operaciones ++ =ref int a) int: (a +:= 1);

Década de 1980

Ada admite la sobrecarga de operadores desde su inicio, con la publicación del estándar de lenguaje Ada 83. Sin embargo, los diseñadores del lenguaje optaron por impedir la definición de nuevos operadores. Solo se pueden sobrecargar los operadores existentes en el idioma, definiendo nuevas funciones con identificadores como "+", "*", "&" etc. Las revisiones posteriores del lenguaje (en 1995 y 2005) mantienen la restricción a la sobrecarga de operadores existentes.

En C++, la sobrecarga de operadores es más refinada que en ALGOL 68.

Década de 1990

Los diseñadores del lenguaje Java de Sun Microsystems optaron por omitir la sobrecarga.

Python permite la sobrecarga de operadores mediante la implementación de métodos con nombres especiales. Por ejemplo, el operador de suma (+) se puede sobrecargar implementando el método obj.__add__(uno mismo, otro).

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.

Años 2000

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 por proxy.

En Raku, la definición de todos los operadores se delega a funciones léxicas y, por lo tanto, al usar definiciones de funciones, los operadores pueden sobrecargarse o agregarse nuevos operadores. Por ejemplo, la función definida en el código fuente de Rakudo para incrementar un objeto Fecha con "+" es:

multi infijo:()Fecha:D $d, Int:D $xFecha.nuevo de día()$d.cuenta de día + $x)
}

Desde que "multi" se utilizó, la función se agrega a la lista de candidatos de multidespacho y "+" solo se sobrecarga en el caso de 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 la sobrecarga varios operadores de llaves: "[x, y]", "x[ y ] ", "x{ y }" y "x( y )".

Kotlin ha admitido la sobrecarga de operadores desde su creación.