martes, 10 de enero de 2017
Capítulo 10. Referencias
Capítulo 10. Referencias
Las referencias Una referencia es otra forma de acceder a un dato, una especie de
alias. Cualquier operacion sobre una referencia afectara a ese dato al que hace referencia.
Figura: sin duda los punteros y las referencias fueron obra de los sarracenos.
Veamos un ejemplo simple:
/**
* Referencias.cpp
* Programa que muestra el uso de referencias
*
* Pello Xabier Altadill Izura
*
* Compilado: g++ Referencias.cpp -o Referencias
*/
using namespace std;
#include
int main() {
// Definimos un dato y su referencia
int numero;
int &referenciaNumero = numero; // Ahi se crea la referencia
cout << "Vamos a ver que pasa si le asignamos un dato: " << endl;
43
Capítulo 10. Referencias
numero = 31337;
// Los dos mostraran el mismo valor
cout << "Valor de numero: " << numero << endl;
cout << "Valor de referenciaNumero: " << referenciaNumero << endl;
// y a donde apuntan? AL MISMO SITIO
cout << "Posicion de numero: " << &numero << endl;
cout << "Posicion de referenciaNumero: " << &referenciaNumero << endl;
cout << "Programa terminado \n" << endl;
return 0;
}
Con los objetos se pueden hacer referencias igualmente:
Objeto miObjeto;
Objeto &refObjeto = miObjeto;
Referencias y funciones Vamos a ver distintas formas de pasar referencias a una funcion.
Como en c, podemos pasar parametros por referencia y hacer que esos parametros
contengan resultados de una funcion.
/**
* ReferenciaFunciones.cpp
* Programa que muestra el uso de referencias en las funciones
*
* Pello Xabier Altadill Izura
*
* Compilado: g++ ReferenciaFunciones.cpp -o ReferenciaFunciones
*/
using namespace std;
#include
// 1Âo funcion que intercambia dos valores
void exchange (int *refa, int *refb);
// 2Âo funcion -sobrecargada- que intercambia dos valores
void exchange (int &refa, int &refb);
int main() {
// Definimos un dato y su referencia
int a, b;
cout << "Asignamos valores: " << endl;
a = 45;
b = 21;
cout << "Valores: a=" << a << " b=" << b << endl;
cout << "Hacemos intercambio con exchange(int *refa, int *refb): " << endl;
exchange(&a, &b); // Con esta llamada invocamos la primera funcion!!
cout << "Valores: a=" << a << " b=" << b << endl;
cout << "Hacemos intercambio con exchange(int &refa, int &refb): " << endl;
xchange(a, b); // Con esta llamada invocamos la segunda funcion!!
out << "Valores: a=" << a << " b=" << b << endl;
44
Capítulo 10. Referencias
out << "Programa terminado \n" << endl;
return 0;
}
// 1Âo funcion que intercambia dos valores
void exchange (int *refa, int *refb) {
int tmp;
tmp = *refa;
*refa = *refb;
*refa = tmp;
}
// 2Âo funcion -sobrecargada- que intercambia dos valores
void exchange (int &refa, int &refb) {
int tmp;
tmp = refa;
refa = refb;
refa = tmp;
}
Pasando clases por referencia
/**
* Gremlin.hpp
*
* Clase que representa el objeto Gremlin.
* Observese el 3Âo metodo constructor
* Pello Xabier Altadill Izura
*
*/
using namespace std;
#include
class Gremlin {
public:
Gremlin();
Gremlin(char *nmb,int ed, int p);
Gremlin(Gremlin&); // atencion a este constructor
~Gremlin();
void correr();
void dormir();
void morder();
int peso;
private:
45
Capítulo 10. Referencias
char *nombre;
int edad;
};
Y su implementacion:
/**
* Gremlin.cpp
*
* Clase que implementa el objeto Gremlin.
* Pello Xabier Altadill Izura
*
*/
#include "Gremlin.hpp"
Gremlin::Gremlin() {
peso = 1;
cout << "Gremlin creado." << endl;
}
Gremlin::Gremlin (char *nmb,int ed, int p) {
nombre = nmb;
edad = ed;
peso = p;
}
Gremlin::~Gremlin() {
cout << "Aaaargh!\nGremlin destruido." << endl;
}
// El gremlin corre
void correr() {
cout << "Jaja grrrr!! jajaja!" << endl;
}
// El gremlin duerme
void dormir() {
cout << "zzzZZZZzzzzz" << endl;
}
// El gremlin muerde
void morder() {
cout << "roaar ñam ñam" << endl;
}
46
Capítulo 10. Referencias
// Definimos esta funcion aparte de la clase
// Con ella el gremlin come y aumenta su atributo peso.
void comer (Gremlin *g) {
// Invocamos la mordedura para que coma
g->morder();
// Le aumentamos 3 unidades por comer
g->peso += 3;
}
// Funcion main
int main () {
cout << "Iniciando programa. " << endl;
// Definimos un gremlin
Gremlin tbautista;
// y lo movemos por la ciudad
tbautista.correr();
tbautista.morder();
// Mostramos su peso
cout << "El gremlin pesa: " << tbautista.peso << endl;
// Le hacemos comer:
comer(&tbautista);
// Mostramos su peso otra vez
cout << "El gremlin pesa ahora: " << tbautista.peso << endl;
cout << "Finalizando programa\n " << endl;
return 0;
}
La ventaja que logramos al pasar parametros por referencia es que ahorramos espacio
en memoria ya que sino en cada llamada a una funcion se hacen copias de los
parametros. Esto tambien tiene una desventaja: si le pasamos a una funcion el ORIGINAL
de un objeto (con una referencia) en lugar de una copia corremos el riesgo de
que la funciona haga trizas nuestro objeto y perder el "original" (supongamos que
la funcion esta hecha por terceros y no sabemos lo que hace). Que se puede hacer
para salvaguardar nuestros objetos? Punteros constantes Esta es la solucion: pasar
punteros constantes. Eso hara que la funcion solo tenga permiso para invocar los
metodos constantes de la clase. SE cambia un poco la clase gremlin para mostrar
esto.
/**
* Gremlin2.hpp
*
* Clase que representa el objeto Gremlin.
* Con un metodo definido como const!!
* Pello Xabier Altadill Izura
*
*/
using namespace std;
#include
47
Capítulo 10. Referencias
class Gremlin {
public:
Gremlin();
Gremlin(char *nmb,int ed, int p);
Gremlin(Gremlin&); // atencion a este constructor
~Gremlin();
void correr();
void dormir();
void morder();
// Definimos una funcion constante
char * getNombre() const;
int peso;
private:
char *nombre;
int edad;
};
Y vemos la implementacion en la que simplemente se puede observar como se protege
el objeto en la funcion comer() gracias al uso de punteros constantes.
/**
* Gremlin2.cpp
*
* Clase que implementa el objeto Gremlin.
* Pello Xabier Altadill Izura
*
*/
#include "Gremlin2.hpp"
Gremlin::Gremlin() {
peso = 1;
cout << "Gremlin creado." << endl;
}
Gremlin::Gremlin (char *nmb,int ed, int p) {
nombre = nmb;
edad = ed;
peso = p;
}
Gremlin::~Gremlin() {
cout << "Aaaargh!\nGremlin destruido." << endl;
48
Capítulo 10. Referencias
}
// El gremlin corre
void correr() {
cout << "Jaja grrrr!! jajaja!" << endl;
}
// El gremlin duerme
void dormir() {
cout << "zzzZZZZzzzzz" << endl;
}
// El gremlin muerde
void morder() {
cout << "roaar ñam ñam" << endl;
}
// FUNCION CONST!!!
// Devuelve el nombre del gremlin
char * getNombre() const {
return nombre;
}
// Definimos esta funcion aparte de la clase
// Con ella el gremlin come y aumenta su atributo peso.
void comer (const Gremlin const *g) {
// Invocamos la mordedura para que coma??
// g->morder(); ERROR no podemos invocar una funcion NO CONSTANTE!!!
// en cambio si podemos invocar getNombre
cout << "Nombre" << g->getNombre() << endl;
}
// Funcion main
int main () {
cout << "Iniciando programa. " << endl;
// Definimos un gremlin
Gremlin tbautista;
// y lo movemos por la ciudad
tbautista.correr();
tbautista.morder();
// Mostramos su peso
cout << "El gremlin pesa: " << tbautista.peso << endl;
// Le hacemos comer:
comer(&tbautista);
49
Capítulo 10. Referencias
// Mostramos su peso otra vez
cout << "El gremlin pesa ahora: " << tbautista.peso << endl;
cout << "Finalizando programa\n " << endl;
return 0;
}
50
Capítulo 11. Funciones avanzadas
Sobrecarga y valores por defecto En un clase se pueden sobrecargar los metodos y
los constructores, e incluso se pueden asignar valores por defecto a los parametros
(como en php). Veamos el ejemplo del coche un poco mas desarrollado.
/**
* Coche.hpp
* Clase que representa un coche
*
* Pello Xabier Altadill Izura
*
*/
using namespace std;
#include
class Coche {
private:
char *marca;
int cilindrada;
int caballos;
enum marcha { Primera, Segunda, Tercera, Cuarta, Quinta, Pto_Muerto};
public:
Coche();
Coche(int cilindrada,int caballos);
Coche(char *marca,int cilindrada,int caballos);
~Coche();
void arranca();
void avanza(int metros = 5); // Con valor por defecto
void cambiaMarcha(marcha mar);
void cambiaMarcha();
void detiene();
void acelera();
char * getMarca ();
int getCilindrada ();
int getCaballos ();
};
Y esta su implementacion observense las funciones sobrecargadas y los posibles errores
que se pueden cometer.
/**
51
Capítulo 11. Funciones avanzadas
* Coche.cpp
* Fichero que implementa la clase coche
*
* Pello Xabier Altadill Izura
*
*/
#include "Coche.hpp";
// Constructor por defecto
Coche::Coche() {
cout << "Coche creado." << endl;
}
// Constructor sobrecargado CON VALORES POR DEFECTO
// si no se establece otra cosa se asignan esos valores
Coche::Coche (int cilindrada = 1000, int caballos = 100) {
this->marca = "Cualquiera";
this->cilindrada = cilindrada;
this->caballos = caballos;
}
// Constructor sobrecargado
Coche::Coche (char *marca,int cilindrada,int caballos) {
this->marca = marca;
this->cilindrada = cilindrada;
this->caballos = caballos;
}
// Destructor
Coche::~Coche() {
cout << "Coche destruido." << endl;
}
void Coche::arranca() {}
void Coche::detiene() {}
void Coche::acelera() {}
// Metodo para que el coche avance. Esta definico con un valor
// por defecto (5) por tanto podria invocarse SIN parametro alguno
void Coche::avanza(int metros) {
cout << this->marca << " ha avanzado " << metros << metros << endl;
}
// Metodo para que el coche cambie de marcha
void Coche::cambiaMarcha() {}
52
Capítulo 11. Funciones avanzadas
// Metodo -sobrecargado- para que el coche cambie de marcha
void Coche::cambiaMarcha(marcha mar) {}
// Muestra la marca
char * Coche::getMarca () {
return this->marca;
}
// Muestra la cilindrada
int Coche::getCilindrada () {
return this->cilindrada;
}
// Muestra los caballos
int Coche::getCaballos (){
return this->caballos;
}
/**
* NOTA IMPORTANTE
* Atencion : al usar esta clase en otra que ya tiene funcion
* main, no se puede tener otra main.
*/
int main () {
int test = 0;
Coche vehiculo = Coche("Skoda", 1050, 250);
cout << "Lo hice, tengo un: "<< vehiculo.getMarca() << endl;
vehiculo.arranca();
vehiculo.cambiaMarcha();
vehiculo.avanza();
// ATENCION!! esto seria una llamada ambigua, ya que existe otro constructor
// que se puede asignar sin parametros pq tiene valores por defecto que es esta:
// Coche::Coche (int cilindrada = 1000, int caballos = 100) y choca con el constructor
// por defecto. Boludos! el compilador nos rompera el ORTO sin compasion
//Coche segundoCoche = Coche();
return 0;
}
Se puede implementar el constructor de otra manera (sirve para tirarte el rollete guru,
aunque te seguiran pagando igual de mal), atencion a la sintaxis.
Coche::Coche(): marca("Seat"), cilindrada(120) {
};
Copy constructor Este es un constructor que se puede añadir a nuestras clases y que
sirve para hacer una copia de un objeto de esa clase. Existe uno por defecto pero es
53
Capítulo 11. Funciones avanzadas
recomendable preocuparse en implementarlo nosotros mismos ya que pueden producirse
errores con atributos que son punteros. Veamos el copy de la clase Perro.
/**
* Perro.hpp
* Clase de cabecera de Perro
*
* Pello Xabier Altadill Izura
*
*/
using namespace std;
#include
class Perro {
public:
Perro (int initialAge);
// constructor COPY
Perro (const Perro &);
~Perro();
// metodos YA implementados
int GetAge() { return itsAge;} // automaticamente inline!
void SetAge (int age) { itsAge = age;} // automaticamente inline!
int * GetPeso() { return peso;} // automaticamente inline!
void SetPeso (int * peso) { this->peso = peso;} // automaticamente inline!
char * GetRaza() { return raza;} // automaticamente inline!
void SetRaza (char * raza) { this->raza = raza;} // automaticamente inline!
char * GetColor() { return color;} // automaticamente inline!
void SetColor (char *color) { this->color = color;} // automaticamente inline!
void Ladra() { cout << "Guau Guau arrr...\n";} // automaticamente inline!
private:
int itsAge;
int *peso;
char *raza;
char *color;
};
Y su implementacion
/**
* Perro.cpp
* Clase que implementa la clase Perro con constructor copy
*
* Pello Xabier Altadill Izura
*
54
Capítulo 11. Funciones avanzadas
* Compilado: g++ Perro.cpp -o Perro
*/
#include "Perro.hpp"
//constructor
Perro::Perro(int initialAge) {
itsAge = initialAge;
cout << "Creado chucho." << endl;
}
//copy-constructor. Atencion
Perro::Perro(const Perro & perroOrigen) {
itsAge = perroOrigen.itsAge;
peso = new int;
raza = new char;
color = new char;
color = perroOrigen.color;
raza = perroOrigen.raza;
peso = perroOrigen.peso;
cout << "Creado chucho con copia" << endl;
}
//destructor
Perro::~Perro() {
cout << " objeto destruido." << endl;
}
/**
* La funcion principal, crea un perro y le hace ladrar
*/
int main()
{
int t = 0;
bool test = false;
Perro Canelo(5);
Canelo.SetRaza("Pastor vasco");
// Creamos a Laika haciendo una copia de canelo
Perro Laika(Canelo);
cout << "Laika es de raza " ;
cout << Laika.GetRaza() << endl;
Laika.SetRaza("Sovietica");
Canelo.Ladra();
cout << "Canelo es un perro cuya edad es: " ;
cout << Canelo.GetAge() << " años\n";
Canelo.Ladra();
Canelo.SetAge(7);
cout << "Ahora Canelo es " ;
55
Capítulo 11. Funciones avanzadas
cout << Canelo.GetAge() << " años\n";
cout << "Laika es de raza " ;
cout << Laika.GetRaza() << endl;
return 0;
}
Sobrecargando operadores Todo un clasico de c++. Podemos sobrecargar operadores
matematicos para nuestras clases. La sintaxis seria algo asi: retorno operator++
(parametros) retorno operator- (parametros) Veamos un ejemplo con la clase
Contador en la que sobrecargamos operadores de prefijo.
/**
* Contador.hpp
* Clase que muestra la sobrecarga de operadores matematicos
*
* Pello Xabier Altadill Izura
*/
using namespace std;
#include
class Contador {
private:
int valor;
public:
Contador();
Contador(int valor);
~Contador();
Contador(const Contador &);
int getContador () const { return valor;} // inline
void setContador (int valor) { this->valor = valor;} // inline
void operator++ (); // operador PREFIJO ++contador
void operator-- (); // operador PREFIJO --contador
void operator++(int); // operador SUFIJO (postfix) contador++
void operator--(int); // operador SUFIJO (postfix) contador--
Contador operator+(const Contador &); // operador +
bool esCero() { return (valor == 0);} // inline
};
Y su implementacion
/**
* Contador.cpp
* fichero que implementa la clase contador
56
Capítulo 11. Funciones avanzadas
*
* Pello Xabier Altadill Izura
*/
#include "Contador.hpp"
// Constructor
Contador::Contador() {
valor = 0;
cout << "Contador creado!" << endl;
}
// Constructor con valor
Contador::Contador(int valor) {
this->valor = valor;
cout << "Contador creado con valor inicial: " << valor << endl;
}
Contador::~Contador() {
cout << "Contador destruido!" << endl;
}
Contador::Contador(const Contador & original) {
valor = original.valor;
}
// Sobrecarga de operador unario ++ PREFIJO ++operador
void Contador::operator++ () {
cout << "incrementando valor de contador : " << valor << endl;
++valor;
}
// Sobrecarga de operador unario -- PREFIJO --operador
void Contador::operator-- () {
cout << "decrementando valor de contador : " << valor << endl;
--valor;
}
// Sobrecarga de operador unario ++ SUFIJO operador++
void Contador::operator++ (int) {
cout << "incrementando valor de contador : " << valor << endl;
valor++;
57
Capítulo 11. Funciones avanzadas
}
// Sobrecarga de operador unario -- SUFIJO operador--
void Contador::operator-- (int) {
cout << "decrementando valor de contador : " << valor << endl;
valor--;
}
// operador +
Contador Contador::operator+(const Contador & tmp) {
return Contador(valor + tmp.getContador());
}
int main () {
int i;
// Definimos un contador
Contador contador;
Contador MegaContador(1687);
Contador resultado;
cout << "Valor de contador: " << contador.getContador() << endl;
// Establecemos un valor inicial
contador.setContador(15);
cout << "Valor de contador: " << contador.getContador() << endl;
cout << "Valor de megacontador: " << MegaContador.getContador() << endl;
// y lo usamos como controlador de un while
while (!contador.esCero()) {
--contador;
}
contador.setContador(1000);
cout << "Valor actual de contador: " << contador.getContador() << endl;
cout << "Valor actual de megacontador: " << MegaContador.getContador() << endl;
resultado = contador + MegaContador;
cout << "Valor de resultado de la suma: " << resultado.getContador() << endl;
return 0;
}
Suscribirse a:
Enviar comentarios (Atom)
No hay comentarios:
Publicar un comentario