Sobrecarga de Operadores: material adaptado de The cplusplus.com tutorial

C++ permite usar operadores estándares como +,-, y * con operandos objetos. De este modo podemos hacer operaciones con instancias de una clase igual como con los tipos fundamentales. Por ejemplo:

int a, b, c;
a = b + c;
es perfectamente válido, dado que las variables son todas tipos fundamentales. Sin embargo, en C no podemos efectuar la operación siguiente (de hecho es incorrecto):
struct { char product [50]; float price; } a, b, c;
a = b + c;   /ERROR en lenguaje C
Lo que conduce a error es el uso del operador adición, que en principio no es válido entre tipos no fundamentales.

En C++, podemos hacer que objetos, instancias de tipos compuestos, como los previos pueden aceptar operadores que de otra manera no serían aceptados. Incluso es posible redefinir el efecto de operadores ya permitidos. La lista de operadores que pueden ser sobrecargados es:

+    -    *    /    =    <    >    +=   -=   *=   /=   <<   >>
<<= >>= == != <= >= ++ -- % & ^ ! |
~ &= ^= |= && || %= [] () new delete
Para sobrecargar un operador, sólo necesitamos escribir una función miembro en la clase cuyo nombre es  operator seguido por el signo del operador que queremos sobrecargar, siguiendo este prototipo:
type operator sign (parameters);
Aquí tenemos un ejemplo que incluye el operador  +. Vamos a sumar vectores bidimensionales a(3,1) y b(1,2). En este caso el resultado será (3+1,1+2) = (4,3).

// vectors: overloading operators example
#include <iostream.h>

class CVector {  // Definición de la clase 
  public:
    int x,y;
    CVector () {};  // debemos incluirlo si implementamos otro contructor
    CVector (int,int);
    CVector operator + (CVector);
};

CVector::CVector (int a, int b) {  // implementación de constructor
  x = a;
  y = b;
}

CVector CVector::operator+ (CVector param) {  // implementación de sobrecarga de operador +
  CVector temp;
  temp.x = x + param.x;
  temp.y = y + param.y;
  return (temp);
}

int main () {
  CVector a (3,1);
  CVector b (1,2);
  CVector c;
  c = a + b;
  cout << c.x << "," << c.y;
  return 0;
}
      
4,3

No se confunda por el hecho de ver muchos  CVector. Uno es el nombre de la clase CVector, otros son nombres de métodos (constructor y destructor - no en este caso ), y otros son valores retornados en métodos. 

CVector (int, int);            // function name CVector (constructor)
CVector operator+ (CVector);   // function operator+ that returns CVector type
  
La función operator+ de la clase CVector es la encargada de sobrecargar el operador aritmético  +. Hay dos formas para llamar esta operación:
c = a + b;   // notar el orden usado para operadores infijos
c = a.operator+(b);  // esta es la forma en que el compilador implementa la línea previa.

Igual como una clase incluye por omisión un constructor de copia y constructor vacío (sin argumentos), ésta también incluye un definición por omisión para el operador de asignación (=) entre dos instancias de la misma clase. Este método copia el contenido bit a bit de los miembros no estáticos del objeto de la derecha al de la izquierda. Por supuesto, podemos redefinir este operador con cualquier otra funcionalidad que se desee; por jemplo, copia en profundidad cuando se tienen atributos punteros.

La sobrecarga de operadores no nos obliga a seguir el mismo significado matemático o usual del operador, aún así es recomendado (por consistencia e interpretación intuitiva). Por ejemplo, no es lógico usar el operador + para restar dos objetos, aún cuando esto sea posible.

El prototipo de la función operator+ puede resultar obvio, pero para otros operadores pueden no serlo. Aquí se tiene una tabla que resume cómo declarar las diferentes funciones de sobrecarga  (reemplace @ por el operador en cada claso):

Expression Comentario
Operator (@) Function member Global function
@a prefijo
+ - * & ! ~ ++ -- A::operator@() operator@(A)
a@ postfijo
++ -- A::operator@(int) operator@(A, int)
a@b infijo
+ - * / % ^ & | < > == != <= >= << >> && || , A::operator@(B) operator@(A, B)
a@b infijo
= += -= *= /= %= ^= &= |= <<= >>= [] A::operator@(B) -
a(b, c...) postfijo
() A::operator()(B, C...) -
a->b infijo
-> A::operator->(B) -
a es un objeto o instancia de clase Ab es una instancia de clase B y c es instancia de calse C. B y C podrían ser tipos básicos.
Se puede ver en esta tabla que algunos operadores se pueden sobrecargar de dos formas: como funciones miembro o método de la clase del operando del lado izquierdo (excepto caso @a) o como funciones globales.
La columna de la derecha (función global) se explica porque es deseable hacer cosas como:
     cout << miObjeto;
como no podemos cambiar la clase ostream, de la cual cout es instancia, no podemos agregar en ella el método
ostream operator<< (MiClase miObjeto) {...}
Para permitir la línea de código previa, C++ permite la sobre carga de algunos operadores vía una función global (es la columna de la derecha). Hay otras situaciones donde la sobrecarga se hace vía función global, por ejemplo, en
Vector v2 = 3*v1; // donde v1 es un vector. No es posible implementar esta operación a través de una sobrecarga de * en clase Vector.
Al optar por sobrecarga vía función global, es muy frecuente necesitar acceder a atributos privados o protegidos de la clase (private o protected).  Por esto y otras situaciones, C++ permite en una clase declarar como amiga funciones globales (friend, se verá más adelante).