Constructor por copia y sobrecarga de operadores.
Implementaremos una clase Complejo, comenzamos con el header de la clase.
En un archivo complejo.h
//-----------------------------------------------------------------------------
// TALLER DE PROGRAMACION I
//
// Temas a ejemplificar: constructor de copia, sobrecarga de operadores
//-----------------------------------------------------------------------------
#ifndef _COMPLEJO_H_
#define _COMPLEJO_H_
#include <ostream>
//-----------------------------------------------------------------------------
// Clase cComplejo: El objetivo de esta clase es el manejo de numeros complejos
//-----------------------------------------------------------------------------
class cComplejo {
private:
int real, imaginario;
// la sobrecarga del operador << no es realizada mediante metodo de
// clase; se declara la funcion como friend (amiga) de la clase de
// forma tal que la misma pueda acceder a la parte no-publica de la clase
friend std::ostream &operator<<( std::ostream &stream, const cComplejo &complejo );
// funcion privada utilizada internamente por los metodos publicos
void set( int real, int imaginario );
public:
// constructor de copia y constructor con parametros con valores por
// default; permiten instancias de los tipos 'cComplejo cmpx2( cmpx1 )',
// 'cComprejo cmpx', 'cComplejo cmpx( 20 )', 'cComplejo cmpx( 20, 10 )'
cComplejo( int real = 0, int imaginario = 0 );
cComplejo( const cComplejo ¶metro );
// sobrecarga del operador = entre dos objetos del tipo cComplejo
const cComplejo &operator=( const cComplejo &origen );
// dos sobrecargas del operador +, para dos tipos de datos distintos
// a la derecha del operador
cComplejo operator+( const cComplejo ¶m ) const;
cComplejo operator+( int param ) const;
// dos sobrecargas del operador +=, para dos tipos de datos distintos
// a la derecha del operador
const cComplejo &operator+=( const cComplejo ¶m );
const cComplejo &operator+=( int param );
// dos sobrecargas del operador ++
// difieren en que una es pre-incremento y la otra post-incremento
cComplejo &operator++();
cComplejo operator++( int );
// sobrecarga de operadores de comparacion. Notar que los dos primeros
// son la base de los siguientes (ver codigo abajo)
bool operator==( const cComplejo ¶m ) const;
bool operator<( const cComplejo ¶m ) const;
bool operator!=( const cComplejo ¶m ) const;
bool operator>( const cComplejo ¶m ) const;
bool operator>=( const cComplejo ¶m ) const;
bool operator<=( const cComplejo ¶m ) const;
// operador de conversion de tipo a int
operator int() const;
};
#endif // _COMPLEJO_H_
Implementación: Escribimos lo siguiente en un archivo complejo.cpp
//-----------------------------------------------------------------------------
// TALLER DE PROGRAMACION I
//
// Temas a ejemplificar: constructor de copia, sobrecarga de operadores
//-----------------------------------------------------------------------------
#include <iostream>
#include "complejo.h"
using std::ostream;
using std::cout;
void cComplejo :: set( int real, int imaginario )
{
// iguala parte real e imaginaria
this->real = real;
this->imaginario = imaginario;
}
cComplejo :: cComplejo( int real, int imaginario ):
real(real), imaginario(imaginario) // Lista de inicializadores
{
}
// en este caso el constructor de copia no es necesario, dado que el
// constructor por default brindado por C++ realizaria el trabajo de
// forma correcta (ver ejemplo de la clase cCadena)
cComplejo :: cComplejo( const cComplejo &c ):
real(c.real), imaginario(c.imaginario)
{
}
const cComplejo &cComplejo :: operator=( const cComplejo &origen )
{
// notar la condicion que evita la auto-asignacion. En este caso no
// seria escencial (ver ejemplo de la clase cCadena)
if( &origen != this ) set( origen.real, origen.imaginario );
return( *this );
}
const cComplejo &cComplejo :: operator+=( const cComplejo ¶m )
{
// sumamos a este objeto el parametro
real += param.real;
imaginario += param.imaginario;
return *this;
}
const cComplejo &cComplejo :: operator+=( int param )
{
real += param;
return *this;
}
cComplejo cComplejo :: operator+( const cComplejo ¶m ) const
{
// notar que los cambios no son almacenados; solo se devuelve un objeto
// temporario con el valor resultante de la operacion
cComplejo resultado(*this); // Copia nuestro objeto
resultado += param; // Reutiliza operator += para sumarle el param
return resultado; // Devuelve la copia
}
cComplejo cComplejo :: operator+( int param ) const
{
// notar que los cambios no son almacenados; solo se devuelve un objeto
// temporario con el valor resultante de la operacion
cComplejo resultado(*this);
resultado += param;
return resultado;
}
cComplejo &cComplejo :: operator++()
{
// operacion de incremento en uno (parte real), pre-incrementada (++a)
// se devuelve referencia para aceptar expresiones del tipo 'a = ++b'
*this += 1;
return( *this );
}
cComplejo cComplejo :: operator++( int )
{
// operacion de incremento en uno (parte real), post-incrementada (a++)
// el parametro (siempre con valor 0) es agregado por el compilador para
// distinguirlo del pre-incremento
// se devuelve un temporario sin modificar, aunque el objeto quede modificado
cComplejo temp = *this;
++(*this); // reutilizamos pre-incremento
return( temp );
}
cComplejo :: operator int() const
{
// la sobrecarga de este operador de 'conversion de tipos' permite
// que el objeto cComplejo se comporte como un 'int' donde
// se requiera este tipo de dato. Dado que fue implementado con fines
// ilustrativos, se retornara solo la parte real
return( real );
}
bool cComplejo :: operator==( const cComplejo ¶m ) const
{
// sobrecarga del operador ==
// se consideran iguales dos complejos con igual parte real e imaginaria
return( (real == param.real) && (imaginario == param.imaginario) );
// NOTA: este operador sobrecargado sera base para el resto
}
bool cComplejo :: operator<( const cComplejo ¶m ) const
{
// sobrecarga del operador <
// se considera un complejo menor que otro si la norma cuadrada del primero
// es menor que la norma cuadrada del segundo
int normacuad1 = real * real + imaginario * imaginario;
int normacuad2 = param.real * param.real +
param.imaginario * param.imaginario;
return( normacuad1 < normacuad2 );
// NOTA: este operador sobrecargado sera base para el resto
}
bool cComplejo :: operator!=( const cComplejo ¶m ) const
{
// sobrecarga del operador !=, utilizando como base el operador ==
return( !( *this == param ) );
}
bool cComplejo :: operator>( const cComplejo ¶m ) const
{
// sobrecarga del operador >, utilizando como base los operadores != y <
return( ( *this != param ) && ( !( *this < param ) ) );
}
bool cComplejo :: operator>=( const cComplejo ¶m ) const
{
// sobrecarga del operador >=, utilizando como base el operador <
return( !( *this < param ) );
}
bool cComplejo :: operator<=( const cComplejo ¶m ) const
{
// sobrecarga del operador <=, utilizando como base el operador >
return( !( *this > param ) );
}
// notar que esta sobrecarga del operador << (no miembro) fue declarada
// como friend de la clase cComplejo; esto es debido a que esta funcion
// accede a atributos privados de la clase. (ver clase cCadena)
ostream &operator<<( ostream &stream, const cComplejo &complejo )
{
// realiza la salida del numero complejo en el formato 'a + bi'
// notar que cout es una instancia de ostream, por lo cual es perfectamente
// valido 'cout << complejo'
stream << "Complejo: " << complejo.real << " + " << complejo.imaginario << "i";
// devuelve una referencia a ostream para permitir expresiones del tipo
// 'cout << a << b << c;
return( stream );
}
Ahora podemos probar los operadores que implementamos:
#include "complejo.h"
int main(void) {
cComplejo a1( 23 );
cComplejo a2( 45, 35 );
cComplejo a3 = a1 + a2;
cout << "\n" << a1 << "\n";
cout << a2 << "\n";
cout << a3 << "\n\n";
a3 += a2;
cout << a3 << "\n";
a3++;
cout << a3 << "\n";
int parte_entera = ++a3;
cout << "La parte entera es ==> " << parte_entera << "\n";
return(0);
}