En C++, la sobrecarga de operadores es un polimorfismo en tiempo de compilación. Es una idea de dar un significado especial a un operador existente en C++ sin cambiar su significado original.
En este artículo, analizaremos más a fondo la sobrecarga de operadores en C++ con ejemplos y veremos qué operadores podemos o no sobrecargar en C++.
Sobrecarga del operador C++
C++ tiene la capacidad de proporcionar a los operadores un significado especial para un tipo de datos; esta capacidad se conoce como sobrecarga de operadores. La sobrecarga de operadores es un polimorfismo en tiempo de compilación. Por ejemplo, podemos sobrecargar un operador '+' en una clase como String para poder concatenar dos cadenas simplemente usando +. Otras clases de ejemplo donde los operadores aritméticos pueden estar sobrecargados son los números complejos, los números fraccionarios, los enteros grandes, etc.
Ejemplo:
int a; float b,sum; sum = a + b;>
Aquí, las variables a y b son de tipos int y float, que son tipos de datos integrados. Por lo tanto, el operador de suma '+' puede sumar fácilmente el contenido de a y b. Esto se debe a que el operador de suma + está predefinido para agregar variables de tipo de datos integrado únicamente.
Implementación:
C++
// C++ Program to Demonstrate the> // working/Logic behind Operator> // Overloading> class> A {> > statements;> };> int> main()> {> > A a1, a2, a3;> > a3 = a1 + a2;> > return> 0;> }> |
si y si no en bash
>
>
En este ejemplo, tenemos 3 variables a1, a2 y a3 de clase de tipo A. Aquí estamos intentando agregar dos objetos a1 y a2, que son de tipo definido por el usuario, es decir, de clase de tipo A usando el operador +. Esto no está permitido porque el operador de suma + está predefinido para operar solo en tipos de datos integrados. Pero aquí, la clase A es un tipo definido por el usuario, por lo que el compilador genera un error. Aquí es donde entra en juego el concepto de sobrecarga del operador.
Ahora, si el usuario quiere que el operador + agregue dos objetos de clase, el usuario tiene que redefinir el significado del operador + de modo que agregue dos objetos de clase. Esto se hace utilizando el concepto de sobrecarga del operador. Entonces, la idea principal detrás de la sobrecarga de operadores es usar operadores de C++ con variables de clase u objetos de clase. Redefinir el significado de los operadores en realidad no cambia su significado original; en cambio, se les ha dado un significado adicional junto con los existentes.
Ejemplo de sobrecarga de operadores en C++
C++
// C++ Program to Demonstrate> // Operator Overloading> #include> using> namespace> std;> class> Complex {> private> :> > int> real, imag;> public> :> > Complex(> int> r = 0,> int> i = 0)> > {> > real = r;> > imag = i;> > }> > // This is automatically called when '+' is used with> > // between two Complex objects> > Complex operator+(Complex> const> & obj)> > {> > Complex res;> > res.real = real + obj.real;> > res.imag = imag + obj.imag;> > return> res;> > }> > void> print() { cout << real <<> ' + i'> << imag <<> '
'> ; }> };> int> main()> {> > Complex c1(10, 5), c2(2, 4);> > Complex c3 = c1 + c2;> > c3.print();> }> |
>
>Producción
12 + i9>
Diferencia entre funciones de operador y funciones normales
Las funciones del operador son las mismas que las funciones normales. Las únicas diferencias son que el nombre de una función de operador es siempre el palabra clave del operador seguido del símbolo del operador, y las funciones del operador se llaman cuando se utiliza el operador correspondiente.
Ejemplo
C++
#include> using> namespace> std;> class> Complex {> private> :> > int> real, imag;> public> :> > Complex(> int> r = 0,> int> i = 0)> > {> > real = r;> > imag = i;> > }> > void> print() { cout << real <<> ' + i'> << imag << endl; }> > // The global operator function is made friend of this> > // class so that it can access private members> > friend> Complex operator+(Complex> const> & c1,> > Complex> const> & c2);> };> Complex operator+(Complex> const> & c1, Complex> const> & c2)> {> > return> Complex(c1.real + c2.real, c1.imag + c2.imag);> }> int> main()> {> > Complex c1(10, 5), c2(2, 4);> > Complex c3> > = c1> > + c2;> // An example call to 'operator+'> > c3.print();> > return> 0;> }> |
>
>Producción
12 + i9>
¿Podemos sobrecargar a todos los operadores?
Casi todos los operadores pueden verse sobrecargados excepto unos pocos. A continuación se muestra la lista de operadores que no se pueden sobrecargar.
sizeof typeid Scope resolution (::) Class member access operators (.(dot), .* (pointer to member operator)) Ternary or conditional (?:)>
Operadores que se pueden sobrecargar en C++
podemos sobrecargar
Operadores unarios Operadores binarios Operadores especiales ( [ ], (), etc)
Pero, entre ellos, hay algunos operadores que no se pueden sobrecargar. Ellos son
Operador de resolución de alcance (: Operador de selección de miembros Selección de miembros mediante *
Puntero a una variable miembro
- Operador condicional (? Tamaño del operador tamaño de ()
Operadores que pueden sobrecargarse | Ejemplos |
---|---|
Aritmética binaria | +, -, *, /, % |
Aritmética unaria | +, -, ++, — |
Asignación | =, +=,*=, /=,-=, %= |
Bit a bit | & , | , <> , ~ , ^ |
De-referencing | (->) |
Asignación de memoria dinámica, De-allocation | Nuevo, eliminar |
Subíndice | [ ] |
Llamada de función | () |
Lógico | &, | |, ! |
Relacional | >, <, = =, = |
¿Por qué no se pueden sobrecargar los operadores mencionados anteriormente?
1. tamaño del operador
Esto devuelve el tamaño del objeto o tipo de datos ingresado como operando. Esto lo evalúa el compilador y no se puede evaluar durante el tiempo de ejecución. El incremento adecuado de un puntero en una matriz de objetos depende implícitamente del operador sizeof. Alterar su significado mediante la sobrecarga provocaría el colapso de una parte fundamental del lenguaje.
2. Operador typeid
Esto proporciona a un programa CPP la capacidad de recuperar el tipo realmente derivado del objeto al que hace referencia un puntero o referencia. Para este operador, el objetivo es identificar de forma única un tipo. Si queremos hacer que un tipo definido por el usuario se parezca a otro tipo, se puede utilizar el polimorfismo, pero el significado del operador typeid debe permanecer inalterado, o de lo contrario podrían surgir problemas graves.
3. Resolución de alcance (::) Operador
Esto ayuda a identificar y especificar el contexto al que se refiere un identificador especificando un espacio de nombres. Se evalúa completamente en tiempo de ejecución y funciona con nombres en lugar de valores. Los operandos de resolución de alcance son expresiones de notas con tipos de datos y CPP no tiene sintaxis para capturarlos si estuviera sobrecargado. Por tanto, es sintácticamente imposible sobrecargar este operador.
4. Operadores de acceso a miembros de la clase (.(punto ), .* (puntero al operador miembro))
La importancia y el uso implícito de los operadores de acceso a miembros de clase se pueden entender a través del siguiente ejemplo:
Ejemplo:
C++
java xor
// C++ program to demonstrate operator overloading> // using dot operator> #include> using> namespace> std;> class> ComplexNumber {> private> :> > int> real;> > int> imaginary;> public> :> > ComplexNumber(> int> real,> int> imaginary)> > {> > this> ->real = real;> > this> ->imaginario = imaginario;> > }> > void> print() { cout << real <<> ' + i'> << imaginary; }> > ComplexNumber operator+(ComplexNumber c2)> > {> > ComplexNumber c3(0, 0);> > c3.real => this> ->real + c2.real;> > c3.imaginary => this> ->imaginario + c2.imaginario;> > return> c3;> > }> };> int> main()> {> > ComplexNumber c1(3, 5);> > ComplexNumber c2(2, 4);> > ComplexNumber c3 = c1 + c2;> > c3.print();> > return> 0;> }> |
>
>Producción
5 + i9>
Explicación:
La declaración NúmeroComplejo c3 = c1 + c2; se traduce internamente como ComplexNumber c3 = c1.operator+ (c2); para invocar la función de operador. El argumento c1 se pasa implícitamente usando el ‘.’ operador. La siguiente declaración también utiliza el operador de punto para acceder a la función miembro print y pasar c3 como argumento.
Además, estos operadores también funcionan con nombres y no con valores y no existe ninguna disposición (sintácticamente) para sobrecargarlos.
5. Operador ternario o condicional (?:)
El operador ternario o condicional es una representación abreviada de una declaración if-else. En el operador, las expresiones verdadero/falso solo se evalúan sobre la base del valor de verdad de la expresión condicional.
conditional statement ? expression1 (if statement is TRUE) : expression2 (else)>
Una función que sobrecarga el operador ternario para una clase, digamos ABC usando la definición
ABC operator ?: (bool condition, ABC trueExpr, ABC falseExpr);>
no podría garantizar que solo una de las expresiones fuera evaluada. Por tanto, el operador ternario no se puede sobrecargar.
Puntos importantes sobre la sobrecarga del operador
1) Para que funcione la sobrecarga de operadores, al menos uno de los operandos debe ser un objeto de clase definido por el usuario.
2) Operador de Asignación: El compilador crea automáticamente un operador de asignación predeterminado con cada clase. El operador de asignación predeterminado asigna todos los miembros del lado derecho al lado izquierdo y funciona bien en la mayoría de los casos (este comportamiento es el mismo que el del constructor de copia). Vea esto para más detalles.
3) Operador de Conversión: También podemos escribir operadores de conversión que se pueden usar para convertir un tipo en otro tipo.
Ejemplo:
C++
// C++ Program to Demonstrate the working> // of conversion operator> #include> using> namespace> std;> class> Fraction {> private> :> > int> num, den;> public> :> > Fraction(> int> n,> int> d)> > {> > num = n;> > den = d;> > }> > // Conversion operator: return float value of fraction> > operator> float> ()> const> > {> > return> float> (num) /> float> (den);> > }> };> int> main()> {> > Fraction f(2, 5);> > float> val = f;> > cout << val <<> '
'> ;> > return> 0;> }> |
>
>Producción
0.4>
Los operadores de conversión sobrecargados deben ser un método miembro. Otros operadores pueden ser el método miembro o el método global.
4) Cualquier constructor al que se pueda llamar con un único argumento funciona como constructor de conversión, lo que significa que también se puede utilizar para la conversión implícita a la clase que se está construyendo.
Ejemplo:
C++
// C++ program to demonstrate can also be used for implicit> // conversion to the class being constructed> #include> using> namespace> std;> class> Point {> private> :> > int> x, y;> public> :> > Point(> int> i = 0,> int> j = 0)> > {> > x = i;> > y = j;> > }> > void> print()> > {> > cout <<> 'x = '> << x <<> ', y = '> << y <<> '
'> ;> > }> };> int> main()> {> > Point t(20, 20);> > t.print();> > t = 30;> // Member x of t becomes 30> > t.print();> > return> 0;> }> |
>
comando de windows arp
>Producción
x = 20, y = 20 x = 30, y = 0>
Cuestionario sobre sobrecarga de operadores