En programación informática , la sobrecarga de operadores , a veces denominada polimorfismo ad hoc de operadores , es un caso específico de polimorfismo , donde diferentes operadores tienen implementaciones distintas según sus argumentos. La sobrecarga de operadores suele estar definida por un lenguaje de programación , un programador o ambos.
Razón fundamental
La sobrecarga de operadores es azúcar sintáctico y se utiliza porque permite programar con una notación más cercana al dominio objetivo [ 1 ] y proporciona a los tipos definidos por el usuario un nivel de soporte sintáctico similar al de los tipos integrados en un lenguaje. Es común, por ejemplo, en la computación científica, donde permite manipular representaciones computacionales 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 puede emularse mediante llamadas a funciones. Por ejemplo, consideremos las variables a, by cde 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 precedencia que el +operador, esta es una forma concisa de escribir:
Add(a, Multiply(b, c))
Sin embargo, la sintaxis anterior refleja el uso matemático común.
Ejemplos
En este caso, el operador de suma se sobrecarga para permitir la suma en un tipo definido por el usuario Timeen C++ :
Operador de tiempo + ( const Tiempo & lhs , const Tiempo & rhs ) { Tiempo temp = lhs ; temp . seconds += rhs . seconds ; temp . minutes += temp . seconds / 60 ; temp . seconds %= 60 ; temp . minutes += rhs . minutes ; temp . hours += temp . minutes / 60 ; temp . minutes %= 60 ; temp . hours += rhs . hours ; return temp ; }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 tempobjeto es el valor devuelto.
La operación también podría definirse como un método de clase, reemplazando lhspor el argumento oculto this; sin embargo, esto obliga a que el operando izquierdo sea de tipo Time:
// El "const" justo antes de la llave de apertura significa que `this` no se modifica. Time Time :: operator + ( const Time & rhs ) const { Time temp = * this ; // `this` no debe modificarse, así que creamos una copia. temp . seconds += rhs . seconds ; temp . minutes += temp . seconds / 60 ; temp . seconds %= 60 ; temp . minutes += rhs . minutes ; temp . hours += temp . minutes / 60 ; temp . minutes %= 60 ; temp . hours += rhs . hours ; return temp ; }Tenga en cuenta que un operador unario definido como un método de clase no recibiría ningún argumento aparente (solo funciona desde this):
bool Time :: operator ! () const { return hours == 0 && minutes == 0 && seconds == 0 ; }El operador menor que (<) se suele sobrecargar para ordenar una estructura o clase:
clase IntegerPair { privado : int x ; int y ; público : explicit IntegerPair ( int x = 0 , int y = 0 ) : x { x }, y { y } {}operador booleano < ( const IntegerPair & p ) const { if ( x == p . x ) { return y < p . y ; } return x < p . x ; } };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 ( operator<), se pueden usar funciones de ordenación estándar para ordenar algunas clases.
A partir de C++20 con la introducción del operador de comparación de tres víasoperator<=> ( ), todos los operadores de orden se pueden definir simplemente definiendo ese operador. El operador de comparación de tres vías existe en muchos lenguajes, incluidos C++ , Python , Rust , Swift y PHP . Otros lenguajes, como Java y C#, en su lugar utilizan un método Comparable.compareTo().
importar std ;usando std :: strong_ordering ;clase IntegerPair { privado : int x ; int y ; público : explicit IntegerPair ( int x = 0 , int y = 0 ) : x { x }, y { y } {}// se puede generar automáticamente con = por defecto; strong_ordering operator < ( const IntegerPair & p ) const { if ( strong_ordering cmp = x <=> p . x ; cmp != strong_ordering :: equal ) { return cmp ; } return y <=> p . y ; } };Críticas
La sobrecarga de operadores ha sido criticada [ 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 bits si y son de tipo entero, pero si es un flujo de salida, el código anterior intentará escribir un en el flujo. Debido a que la sobrecarga de operadores permite al programador original cambiar la semántica habitual de un operador y sorprender a cualquier programador posterior, se considera una buena práctica usar la sobrecarga de operadores con cuidado (los creadores de Java decidieron no usar esta característica, [ 3 ] aunque no necesariamente por esta razón ).a<<bababab
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 sobrecarga comúnmente para realizar una concatenación de cadenas (es decir, "bird" + "song"produce "birdsong", mientras que "song" + "bird"produce "songbird"). Un contraargumento típico a este argumento proviene directamente de las matemáticas: mientras que + es conmutativo en 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 .
Catalogar
Se realiza 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.
Cronología de la sobrecarga de operadores
década de 1960
La especificación ALGOL 68 permitía la sobrecarga del operador. [ 36 ]
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 booleanos a) op ∨ = ( bool a, b) bool :( a | true | b ); b) op ∧ = ( bool a, b) bool : ( a | b | false ); c) op ¬ = ( bool a) bool : ( a | false | true ); 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:
prioridad máxima = 9; op max = ( int a, b) int : ( a>b | a | b ); op ++ = ( ref int a ) int : ( a +:= 1 );
década de 1980
Ada admite la sobrecarga de operadores desde sus inicios, con la publicación del estándar del 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, 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. [ 37 ]
década de 1990
Los diseñadores del lenguaje Java en Sun Microsystems optaron por omitir la sobrecarga. [ 38 ] [ 39 ] [ 40 ] Cuando se le preguntó sobre la sobrecarga de operadores, Brian Goetz de Oracle respondió: " Primero los tipos de valor , luego podemos hablar de ello", sugiriendo que potencialmente podría agregarse después del Proyecto Valhalla . [ 41 ]
Python permite la sobrecarga de operadores mediante la implementación de métodos con nombres especiales. [ 42 ] 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 las llamadas a métodos, con la característica adicional de que si el primer operando no define ese operador, se utilizará el método del segundo operando.
década de 2000
Microsoft añadió la sobrecarga de operadores a C# en 2001 y a Visual Basic .NET en 2003. La sobrecarga de operadores de C# es muy similar en sintaxis a la sobrecarga de operadores de C++: [ 43 ]
clase pública Fracción { numerador entero privado ; denominador entero privado ;// ...public static Fraction operator + ( Fraction lhs , Fraction rhs ) => new Fraction ( lhs . numerator * rhs . denominator + rhs . numerator * lhs . denominator , lhs . denominator * rhs . denominator ); }Scala trata a todos los operadores como métodos y, por lo tanto, permite la sobrecarga de operadores por medio de un proxy.
década de 2010
En Raku , la definición de todos los operadores se delega a funciones léxicas, por lo que, utilizando definiciones de funciones, se pueden sobrecargar los operadores o agregar nuevos operadores. Por ejemplo, la función definida en el código fuente de Rakudo para incrementar un objeto Date con " +" es:
multi infijo:<+> ( Fecha:D $d , Entero:D $x ) { Fecha . nuevo-desde-contador-días ( $d . contador-días + $x ) } Dado que se utilizó "multi", la función se agrega a la lista de candidatos de despacho 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érminoi , etc., también permite sobrecargar varios operadores de llaves: [x, y], x[y], x{y}, y x(y).
Kotlin ha admitido la sobrecarga de operadores desde su creación sobrescribiendo funciones con nombres especiales (como plus(), inc(), rangeTo(), etc.) [ 44 ]
clase de datos Punto ( val x : Int , val y : Int ) { operador fun plus ( other : Punto ): Punto { return Punto ( this . x + other . x , this . y + other . y ) } }Dado que tanto Kotlin como Java se compilan a .class , cuando se convierten de nuevo a Java , esto se representará simplemente como:
clase pública Punto { // campos y constructor...public Point plus ( Point other ) { return new Point ( this . x + other . x , this . y + other . y ); } }La sobrecarga de operadores en Rust se logra implementando los rasgos en std::ops. [ 45 ]
usar std :: ops :: Add ;#[derive(Debug)] struct Point { x : i32 , y : i32 }impl Point { pub fn new ( x : i32 , y : i32 ) -> Self { Point { x , y } } }impl Agregar para Punto { tipo Salida = Punto ;fn add ( self , other : Point ) -> Point { Point { x : self . x + other . y , y : self . y + other . y } } }fn main () { let p1 : Point = Point :: new ( 1 , 2 ); let p2 : Point = Point :: new ( 3 , 4 ); let sum : Point = p1 + p2 ; println! ( "Suma de p1 y p2: {:?}" , sum ); }Véase también
Referencias
- ↑ Stroustrup, Bjarne . "Operator Overloading" . Preguntas frecuentes de C++ . Archivado del original el 14 de agosto de 2011. Consultado el 27 de agosto de 2020 .
- ↑ Fisher, Charles N. (2008). "Problemas de sobrecarga" (PDF) . Universidad de Wisconsin-Madison .
- ↑ "No más sobrecarga de operadores" . El entorno del lenguaje Java . Oracle Corporation .
- ↑ Se pueden añadir operadores completamente nuevos.
- ↑ "Predicado op/3" .
- ↑ "Bertrand Meyer: Mecanismos básicos del lenguaje Eiffel" . se.ethz.ch. Consultado el 7 de abril de 2021 .
- ↑ "Funciones de operador en F90" . www.mathcs.emory.edu . Archivado del original el 11 de agosto de 2021. Consultado el 7 de abril de 2021 .
- ↑ Introducido en Fortran 90.
- ↑ Smith, Chris (9 de octubre de 2012). Programación en F# 3.0: Una guía completa para escribir código sencillo que resuelva problemas complejos . O'Reilly Media, Inc. ISBN 978-1-4493-2604-3.
- ↑ Clases de tipos en lugar de sobrecarga.
- ↑ "Sobrecarga de operadores en Julia" . geeksforgeeks.org . Consultado el 14 de marzo de 2025 .
- ↑ "Operadores - R en pocas palabras, 2.ª edición [ Libro ] " . www.oreilly.com . Consultado el 7 de abril de 2021 .
- ↑ "Operadores" . Recorrido por Scala .
- ↑ Hunt, John (6 de diciembre de 2012). Smalltalk y la orientación a objetos: una introducción . Springer Science & Business Media. ISBN 978-1-4471-0961-7.
- ↑ "Swift: Operadores avanzados" .
- ↑ "¿Por qué Go no admite la sobrecarga de métodos y operadores?" . Consultado el 4 de septiembre de 2011 .
- ↑ "Introducción" . freepascal.org . Consultado el 30 de septiembre de 2020 .
- ↑ "Sobrecarga de operadores" . GitHub . Consultado el 28 de septiembre de 2018 .
- ↑ "6.6 Sobrecarga de operadores" . Manual de referencia de Ada anotado .
- ^ Drayton, Peter; Albahari, Ben; Neward, Ted (2003). C# en pocas palabras . O'Reilly Media, Inc. ISBN 978-0-596-00526-9.
- ↑ "Sobrecarga de operadores en C++" .
- ↑ "Sobrecarga de operadores - Lenguaje de programación D" . dlang.org . Consultado el 10 de octubre de 2020 .
- ↑ "Un recorrido por el lenguaje Dart" . dart.dev . Consultado el 30 de septiembre de 2020 .
- ↑ "El lenguaje de programación Apache Groovy - Operadores" . groovy-lang.org . Consultado el 30 de septiembre de 2020 .
- ↑ "Sobrecarga de operadores" . Kotlin . Consultado el 24 de junio de 2018 .
- ↑ "Tutorial de metamétodos" . Wiki de usuarios de Lua .
- ↑ "Implementación de operadores para su clase" . Archivado del original el 14 de junio de 2024. Consultado el 1 de octubre de 2013 .
- ↑ "Sobrecarga de operadores" . Manual de Free Pascal . Consultado el 1 de diciembre de 2014 .
- ↑ "Sobrecarga del operador" . Manual de Delphi . Consultado el 1 de diciembre de 2014 .
- ↑ "Métodos mágicos de PHP que sobrescriben propiedades de clase" . Archivado del original el 4 de marzo de 2016. Consultado el 7 de abril de 2015 .
- ↑ Orwant, Jon (4 de noviembre de 2002). Computer Science & Perl Programming: Best of The Perl Journal . O'Reilly Media, Inc. págs. 347–. ISBN 978-0-596-00310-4.
- ↑ "3. Modelo de datos" . Referencia del lenguaje Python .
- ↑ "Métodos" . Preguntas frecuentes oficiales de Ruby .
- ↑ "Sobrecarga de operadores" . Rust por ejemplo .
- ↑ "Cómo: Definir un operador (Visual Basic)" . 15 de septiembre de 2021.
- ↑ van Wijngaarden, A.; Mailloux, Barry J.; Peck, John EL ; Koster, Cornelis HA ; et al. (Agosto de 1968). "Informe sobre el lenguaje algorítmico ALGOL 68, sección 10.2.2" (PDF) . Consultado el 1 de abril de 2007 .
- ↑ Stroustrup, Bjarne . "Una historia de C++: 1979−1991" (PDF) . pág. 12. Consultado el 1 de abril de 2007 .
- ↑ "Pregunta frecuente 6.9: ¿Por qué no hay sobrecarga de operadores?" . La lista de preguntas frecuentes de comp.lang.java .
- ↑ "java.sun.com" . Archivado del original el 7 de marzo de 2009. Consultado el 26 de marzo de 2009 .
- ^ Holzner, Steven (2001). C++: Libro Negro . Scottsdale, Arizona: Grupo Coriolis. pag. 387.ISBN 1-57610-777-9
Una de las mejores características de la programación orientada a objetos en C++ es que puedes sobrecargar operadores para manejar objetos de tus clases (esto no se puede hacer en otros lenguajes centrados en la programación orientada a objetos, como Java)
. - ↑ @BrianGoetz (11 de enero de 2017). "Primero los tipos de valor, luego podemos hablar de ello" ( Tweet ) – vía Twitter .
- ↑ "3. Modelo de datos, nombres de métodos especiales" . La referencia del lenguaje Python .
- ↑ "Sobrecarga de operadores: operadores unarios, aritméticos, de igualdad y de comparación predefinidos" . learn.microsoft.com . Microsoft Learn. 13 de junio de 2025.
- ↑ "Sobrecarga de operadores en Kotlin" . kotlinlang.org . JetBrains sro . Consultado el 15 de octubre de 2025 .
- ↑ "Sobrecarga de operadores - Rust mediante ejemplos" . doc.rust-lang.org . Lenguaje de programación Rust . Consultado el 15 de octubre de 2025 .
- Operadores (programación)