Anuncios

Hola, a todos sean bienvenidos a mi nuevo post. Hoy continuaremos con lo iniciado en el post anterior, para comenzar pasaremos a hablar de herencia privada, como vimos hasta ahora si haciamos una herencia era del tipo publico, es decir todas las clases herederas tienen acceso a las funciones miembro de la clase base pero si nosotros necesitaramos restringir o compartir especificamente algunas funciones miembro utilizaremos la herencia de tipo privada, veamos el siguiente ejemplo para luego desarrollar su explicacion:

advher03.cpp

# include <iostream>

using namespace std;

class Pieza
{
public:
 	Pieza(): suNumeroPieza(1){}
 	Pieza(int NumeroPieza):
 	suNumeroPieza(NumeroPieza){}
 	virtual ~Pieza(){}
 	int ObtenerNumeroPieza() const { return suNumeroPieza; }
 	virtual void Desplegar() const = 0;
private:
 	int suNumeroPieza;
};

void Pieza::Desplegar() const
{
 	cout << "\nNumero de Pieza: " << suNumeroPieza << endl;
}

class PiezaAuto : public Pieza
{
public:
 	PiezaAuto(): suAnioModelo(94){}
 	PiezaAuto(int anio, int numeroPieza);
 	virtual void Desplegar() const
 	{
 		Pieza::Desplegar();
 		cout << "Año del modelo: ";
 		cout << suAnioModelo << endl;
 	}
private:
 	int suAnioModelo;
};

PiezaAuto::PiezaAuto(int anio, int numeroPieza):
 	suAnioModelo(anio),
 	Pieza(numeroPieza)
 	{}

class PiezaAeroPlano : public Pieza
{
public:
 	PiezaAeroPlano(): suNumeroMotor(1){}
 	PiezaAeroPlano(int NumeroMotor, int NumeroPieza);
 	virtual void Desplegar() const
 	{
 		Pieza::Desplegar();
 		cout << "Motor Numero: ";
 		cout << suNumeroMotor << endl;
 	}
private:
 	int suNumeroMotor;
};

PiezaAeroPlano::PiezaAeroPlano(int NumeroMotor, int NumeroPieza):
 	suNumeroMotor(NumeroMotor),
 	Pieza(NumeroPieza)
 	{}

class NodoPieza
{
public:
 	NodoPieza(Pieza *);
 	~NodoPieza();
 	void AsignarSiguiente(NodoPieza * nodo) { suSiguiente = nodo; }
 	NodoPieza * ObtenerSiguiente() const;
 	Pieza * ObtenerPieza() const;
private:
 	Pieza * suPieza;
 	NodoPieza * suSiguiente;
};

NodoPieza::NodoPieza(Pieza * apPieza):
 	suPieza(apPieza),
 	suSiguiente(0)
 	{}

NodoPieza::~NodoPieza()
{
 	delete suPieza;
 	suPieza = NULL;
 	delete suSiguiente;
 	suSiguiente = NULL;
}

NodoPieza * NodoPieza::ObtenerSiguiente() const { return suSiguiente; }

Pieza * NodoPieza::ObtenerPieza() const
{
 	if (suPieza)
 		return suPieza;
 	else
 		return NULL;
}

class ListaPiezas
{
public:
 	ListaPiezas();
 	~ListaPiezas();
 	void Iterar(void (Pieza::*f)() const) const;
 	Pieza * Encontrar(int & posicion, int NumeroPieza) const;
 	Pieza * ObtenerPrimero() const;
 	void Insertar(Pieza *);
 	Pieza * operator[](int) const;
 	int ObtenerCuenta() const { return suCuenta; }
 	static ListaPiezas& ObtenerListasPiezasGlobal() { return ListaPiezasGlobal; }
private:
 	NodoPieza * apCabeza;
 	int suCuenta;
 	static ListaPiezas ListaPiezasGlobal;
};

ListaPiezas ListaPiezas::ListaPiezasGlobal;

ListaPiezas::ListaPiezas():
 	apCabeza(0),
 	suCuenta(0)
 	{}

ListaPiezas::~ListaPiezas() { delete apCabeza; }

Pieza *ListaPiezas::ObtenerPrimero() const
{
 	if (apCabeza)
 		return apCabeza->ObtenerPieza();
 	else
 		return NULL;
}

Pieza * ListaPiezas::operator[](int desplazamiento) const
{
 	NodoPieza * apNodo = apCabeza;
 	if (!apCabeza)
 		return NULL;
 	if (desplazamiento > suCuenta)
 		return NULL;
 	for(int i = 0; i < desplazamiento; i++)
 		apNodo = apNodo->ObtenerSiguiente();
 	return apNodo->ObtenerPieza();
}

Pieza *ListaPiezas::Encontrar(int & posicion, int NumeroPieza) const
{
 	NodoPieza * apNodo = NULL;
	for(apNodo = apCabeza, posicion = 0; apNodo!=NULL;
 		apNodo = apNodo->ObtenerSiguiente(), posicion++)
 	{
 		if (apNodo->ObtenerPieza()->ObtenerNumeroPieza() == NumeroPieza)
 			break;
 	}
 	if (apNodo == NULL)
 		return NULL;
 	else
 		return apNodo->ObtenerPieza();
}

void ListaPiezas::Iterar(void (Pieza::*func)() const) const
{
 	if (!apCabeza)
 		return;
 	NodoPieza * apNodo = apCabeza;
 	do
 	(apNodo->ObtenerPieza()->*func)();
 	while(apNodo = apNodo->ObtenerSiguiente());
}

void ListaPiezas::Insertar(Pieza * apPieza)
{
 	NodoPieza * apNodo = new NodoPieza(apPieza);
 	NodoPieza * apActual = apCabeza;
 	NodoPieza * apSiguiente = NULL;
 	int Nuevo = apPieza -> ObtenerNumeroPieza();
 	int Siguiente = 0;
	suCuenta++;
 	if (!apCabeza)
 	{
 		apCabeza=apNodo;
 		return;
 	}
	if (apCabeza->ObtenerPieza()->ObtenerNumeroPieza() > Nuevo)
 	{
 		apNodo->AsignarSiguiente(apCabeza);
 		apCabeza = apNodo;
 		return;
 	}
 	for(;;)
 	{
 		if (!apActual->ObtenerSiguiente())
 		{
 			apActual->AsignarSiguiente(apNodo);
 			return;
 		}
 		apSiguiente = apActual->ObtenerSiguiente();
 		Siguiente = apSiguiente->ObtenerPieza()->ObtenerNumeroPieza();
 		if (Siguiente > Nuevo)
 		{
 			apActual->AsignarSiguiente(apNodo);
 			apNodo->AsignarSiguiente(apSiguiente);
 			return;
 		}
 		apActual = apSiguiente;
 	}
}

class CatalogoPiezas : private ListaPiezas
{
public:
 	void Insertar(Pieza *);
 	int Existe(int NumeroPieza);
 	Pieza * Obtener(int NumeroPieza);
 	int operator+(const CatalogoPiezas &);
 	void MostrarTodo() { Iterar(&Pieza::Desplegar); }
private:
};

void CatalogoPiezas::Insertar(Pieza * nuevaPieza)
{
 	int numeroPieza = nuevaPieza->ObtenerNumeroPieza();
 	int desplazamiento;
	if (!Encontrar(desplazamiento, numeroPieza))
 		ListaPiezas::Insertar(nuevaPieza);
 	else
 	{
 		cout << numeroPieza << " fue la ";
 		switch(desplazamiento)
 		{
 			case 0: cout << "primera "; break;
 			case 1: cout << "segunda "; break;
 			case 2: cout << "tercera "; break;
 			default: cout << desplazamiento+1 << "a "; break;
 		}
 		cout << "entrada. Rechazada!\n";
 	}
}

int CatalogoPiezas::Existe(int NumeroPieza)
{
 	int desplazamiento;
 	Encontrar(desplazamiento, NumeroPieza);
 	return desplazamiento;
}

Pieza * CatalogoPiezas::Obtener(int NumeroPieza)
{
 	int desplazamiento;
	return (Encontrar(desplazamiento,NumeroPieza));
}

int main()
{
 	CatalogoPiezas cp;
 	Pieza * apPieza = NULL;
 	int NumeroPieza;
 	int valor;
 	int opcion;
	while(1)
 	{
 		cout << "(0)Salir (1)Auto (2)Avion: ";
 		cin >> opcion;
		if(!opcion)
 			break;
 		cout << "Nuevo Numero de Pieza?: ";
 		cin >> NumeroPieza;
 		if (opcion == 1)
 		{
 			cout << "Año del modelo?: ";
 			cin >> valor;
 			apPieza = new PiezaAuto(valor,NumeroPieza);
 		}
 		else
 		{
 			cout << "Numero de Motor?: ";
 			cin >> valor;
 			apPieza = new PiezaAeroPlano(valor, NumeroPieza);
 		}
 		cp.Insertar(apPieza);
 	}
 	cp.MostrarTodo();
 	return 0;
}
Anuncios

Este codigo es muy parecido al visto en el post anterior, con la salvedad de que convertimos a ListaPiezas en una clase «base» porque haremos a CatalogoPiezas heredera de ListaPiezas de forma privada, es decir vamos a seguir teniendo una clase base llamada Pieza, dos clases derivadas de esta, PiezaAuto y PiezaAeroPlano, las cuales se encargaran de mostrar el valor del año del modelo o numero de motor, respectivamente, tambien tendremos una clase llamada NodoPieza encargada de crear y administrar una lista enlazada, luego tendremos la clase ListaPiezas, esta clase se encargara de la mayoria de las acciones, estas van a ser Encontrar(), Iterar() e Insertar(), la siguiente clase sera CatalogoPiezas, la cual ahora la haremos heredera de ListaPiezas pero como nosotros no necesitamos tener un acceso total a las funciones de ListaPiezas lo declararemos como privado, a diferencia del codigo del post anterior ya no necesitamos tener en privado creado un objeto del tipo ListaPiezas, veamos las diferencias:

CatalogoPiezas de advher02.cpp:

class CatalogoPiezas
{
public:
void Insertar(Pieza *);
int Existe(int NumeroPieza);
Pieza * Obtener(int NumeroPieza);
int operator+(const CatalogoPiezas &);
void MostrarTodo() { laListaPiezas.Iterar(&Pieza::Desplegar); }
private:
ListaPiezas laListaPiezas;
};

La misma clase pero en advher03.cpp

class CatalogoPiezas : private ListaPiezas
{ 
public:
void Insertar(Pieza *);
int Existe(int NumeroPieza);
Pieza * Obtener(int NumeroPieza);
int operator+(const CatalogoPiezas &);
void MostrarTodo(){ Iterar(&Pieza::Desplegar); }
private:
};
Anuncios

En este caso es la declaracion de la clase CatalogoPiezas, en el primer caso lo mas notorio es el encabezado donde no hereda ninguna clase base y en private, tiene un objeto del tipo ListaPiezas para poder tener acceso a las funciones miembro de ListaPiezas, en el ejemplo actual lo declaramos como heredera de ListaPiezas, esto nos permitira tener acceso a las funciones miembro y por ende no necesitamos crear un objeto de tipo ListaPiezas y por esto private queda vacio, si no estuviera seria lo mismo pero lo muestro para observar la diferencia, veamos otro bloque:

Bloque de advher02.cpp:

if (!laListaPiezas.Encontrar(desplazamiento, numeroPieza))
	laListaPiezas.Insertar(nuevaPieza);
else
{
	cout << numeroPieza << ” fue la “;
	switch(desplazamiento)
	{
		case 0: cout << “primera “; break;
		case 1: cout << “segunda “; break;
		case 2: cout << “tercera “; break;
		default: cout << desplazamiento+1 << “a “; break;
	}
	cout << “entrada. Rechazada!\n”;
}

El mismo bloque en advher03.cpp

if (!Encontrar(desplazamiento, numeroPieza))
  	ListaPiezas::Insertar(nuevaPieza);
else
{
  	cout << numeroPieza << " fue la ";
  	switch(desplazamiento)
  	{
  		case 0: cout << "primera "; break;
  		case 1: cout << "segunda "; break;
  		case 2: cout << "tercera "; break;
  		default: cout << desplazamiento+1 << "a "; break;
  	}
  	cout << "entrada. Rechazada!\n";
}
Anuncios

En el primer bloque llamamos a la funcion Encontrar() miembro del objeto creado de la clase ListaPiezas, y luego usamos la funcion Insertar() de la clase ListaPiezas, todo gracias al objeto creado. En el ejemplo actual, como nosotros lo hicimos heredero de ListaPiezas, podemos llamarlo directamente y a Insertar() tambien tenemos acceso por la ruta completa, pasenos al siguiente bloque modificado:

Analicemos el siguiente bloque de advher02.cpp:

int CatalogoPiezas::Existe(int NumeroPieza)
{
  	int desplazamiento;
 	laListaPiezas.Encontrar(desplazamiento, NumeroPieza);
 	return desplazamiento;
}

El mismo bloque en advher03.cpp:

int CatalogoPiezas::Existe(int NumeroPieza)
{
  	int desplazamiento;
 	Encontrar(desplazamiento, NumeroPieza);
 	return desplazamiento;
}
Anuncios

Al igual que en el caso anterior no es necesario el acceder por medio del objeto creado de tipo ListaPiezas sino que podemos invocarlo directamente, analicemos el ultimo bloque:

Bloque de advher02.cpp:

Pieza * CatalogoPiezas::Obtener(int NumeroPieza)
{
  	int desplazamiento;
	Pieza * laPieza = laListaPiezas.Encontrar(desplazamiento,NumeroPieza);
 	return laPieza;
}

El mismo bloque pero en advher03.cpp:

Pieza * CatalogoPiezas::Obtener(int NumeroPieza)
{
  	int desplazamiento;
	return (Encontrar(desplazamiento,NumeroPieza));
}
Anuncios

En este caso es similar a los anteriores pero con una salvedad, en el ejemplo anterior nosotros debiamos crear un objeto del tipo Pieza para regresar el valor obtenido por parte de la funcion Encontrar() de la clase ListaPiezas, ahora como es heredera de esta no es necesario crear otro objeto del tipo Pieza sino retornando directamente el valor, despues el resto del programa sigue igual para preguntarnos los valores a ingresar, la salida es asi:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./advher03
(0)Salir (1)Auto (2)Avion: 1
Nuevo Numero de Pieza?: 110011
Año del modelo?: 2010
(0)Salir (1)Auto (2)Avion: 2
Nuevo Numero de Pieza?: 220022
Numero de Motor?: 2012
(0)Salir (1)Auto (2)Avion: 1
Nuevo Numero de Pieza?: 220022
Año del modelo?: 2012
220022 fue la segunda entrada. Rechazada!
(0)Salir (1)Auto (2)Avion: 1
Nuevo Numero de Pieza?: 330033
Año del modelo?: 2014
(0)Salir (1)Auto (2)Avion: 0

Numero de Pieza: 110011
Año del modelo: 2010

Numero de Pieza: 220022
Motor Numero: 2012

Numero de Pieza: 330033
Año del modelo: 2014
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Como pueden ver es igual, la unica modificacion mas notable es el hecho de no tener que crear tantos objetos para poder acceder a las funciones de cada una de las clases, es decir la herencia del tipo privada permite una forma eficaz de acceso a las funciones, por ejemplo CatalogoPiezas puede tener acceso a las funciones a utilizar pero todavia proporciona un acceso controlado al metodo Insertar() de ListaPiezas y a otros metodos  en los cuales las clases clientes no deben tener un acceso directo. para nuestro siguiente caso hablaremos sobre clases amigas pero antes analicemos el siguiente codigo:

advher04.cpp

# include <iostream>

using namespace std;

class Pieza
{
public:
 	Pieza(): suNumeroPieza(1){}
 	Pieza(int NumeroPieza):
 	suNumeroPieza(NumeroPieza){}
 	virtual ~Pieza(){}
 	int ObtenerNumeroPieza() const { return suNumeroPieza; }
 	virtual void Desplegar() const = 0;
private:
 	int suNumeroPieza;
};

void Pieza::Desplegar() const
{
 	cout << "\nNumero de Pieza: " << suNumeroPieza << endl;
}

class PiezaAuto : public Pieza
{
public:
 	PiezaAuto(): suAnioModelo(94){}
 	PiezaAuto(int anio, int numeroPieza);
 	virtual void Desplegar() const
 	{
 		Pieza::Desplegar();
 		cout << "Año del modelo: ";
 		cout << suAnioModelo << endl;
 	}
private:
 	int suAnioModelo;
};

PiezaAuto::PiezaAuto(int anio, int numeroPieza):
 	suAnioModelo(anio),
 	Pieza(numeroPieza)
 	{}

class PiezaAeroPlano : public Pieza
{
public:
 	PiezaAeroPlano(): suNumeroMotor(1){}
 	PiezaAeroPlano(int NumeroMotor, int NumeroPieza);
 	virtual void Desplegar() const
 	{
 		Pieza::Desplegar();
 		cout << "Motor Numero: ";
 		cout << suNumeroMotor << endl;
 	}
private:
 	int suNumeroMotor;
};

PiezaAeroPlano::PiezaAeroPlano(int NumeroMotor, int NumeroPieza):
 	suNumeroMotor(NumeroMotor),
 	Pieza(NumeroPieza)
 	{}

class NodoPieza
{
public:
	friend class ListaPiezas;
 	NodoPieza(Pieza *);
 	~NodoPieza();
 	void AsignarSiguiente(NodoPieza * nodo) { suSiguiente = nodo; }
 	NodoPieza * ObtenerSiguiente() const;
 	Pieza * ObtenerPieza() const;
private:
 	Pieza * suPieza;
 	NodoPieza * suSiguiente;
};

NodoPieza::NodoPieza(Pieza * apPieza):
 	suPieza(apPieza),
 	suSiguiente(0)
 	{}

NodoPieza::~NodoPieza()
{
 	delete suPieza;
 	suPieza = NULL;
 	delete suSiguiente;
 	suSiguiente = NULL;
}

NodoPieza * NodoPieza::ObtenerSiguiente() const { return suSiguiente; }

Pieza * NodoPieza::ObtenerPieza() const
{
 	if (suPieza)
 		return suPieza;
 	else
 		return NULL;
}

class ListaPiezas
{
public:
 	ListaPiezas();
 	~ListaPiezas();
 	void Iterar(void (Pieza::*f)() const) const;
 	Pieza * Encontrar(int & posicion, int NumeroPieza) const;
 	Pieza * ObtenerPrimero() const;
 	void Insertar(Pieza *);
 	Pieza * operator[](int) const;
 	int ObtenerCuenta() const { return suCuenta; }
 	static ListaPiezas& ObtenerListasPiezasGlobal() { return ListaPiezasGlobal; }
private:
 	NodoPieza * apCabeza;
 	int suCuenta;
 	static ListaPiezas ListaPiezasGlobal;
};

ListaPiezas ListaPiezas::ListaPiezasGlobal;

ListaPiezas::ListaPiezas():
 	apCabeza(0),
 	suCuenta(0)
 	{}

ListaPiezas::~ListaPiezas() { delete apCabeza; }

Pieza *ListaPiezas::ObtenerPrimero() const
{
 	if (apCabeza)
 		return apCabeza->suPieza;
 	else
 		return NULL;
}

Pieza * ListaPiezas::operator[](int desplazamiento) const
{
 	NodoPieza * apNodo = apCabeza;
 	if (!apCabeza)
 		return NULL;
 	if (desplazamiento > suCuenta)
 		return NULL;
 	for(int i = 0; i < desplazamiento; i++)
 		apNodo = apNodo->suSiguiente;
 	return apNodo->suPieza;
}

Pieza *ListaPiezas::Encontrar(int & posicion, int NumeroPieza) const
{
 	NodoPieza * apNodo = NULL;
	for(apNodo = apCabeza, posicion = 0; apNodo!=NULL;
 		apNodo = apNodo->suSiguiente, posicion++)
 	{
 		if (apNodo->suPieza->ObtenerNumeroPieza() == NumeroPieza)
 			break;
 	}
 	if (apNodo == NULL)
 		return NULL;
 	else
 		return apNodo->suPieza;
}

void ListaPiezas::Iterar(void (Pieza::*func)() const) const
{
 	if (!apCabeza)
 		return;
 	NodoPieza * apNodo = apCabeza;
 	do
 	(apNodo->ObtenerPieza()->*func)();
 	while(apNodo = apNodo->suSiguiente);
}

void ListaPiezas::Insertar(Pieza * apPieza)
{
 	NodoPieza * apNodo = new NodoPieza(apPieza);
 	NodoPieza * apActual = apCabeza;
 	NodoPieza * apSiguiente = NULL;
 	int Nuevo = apPieza -> ObtenerNumeroPieza();
 	int Siguiente = 0;
	suCuenta++;
 	if (!apCabeza)
 	{
 		apCabeza=apNodo;
 		return;
 	}
	if (apCabeza->suPieza->ObtenerNumeroPieza() > Nuevo)
 	{
 		apNodo->suSiguiente=apCabeza;
 		apCabeza = apNodo;
 		return;
 	}
 	for(;;)
 	{
 		if (!apActual->suSiguiente)
 		{
 			apActual->suSiguiente=apNodo;
 			return;
 		}
 		apSiguiente = apActual->suSiguiente;
 		Siguiente = apSiguiente->suPieza->ObtenerNumeroPieza();
 		if (Siguiente > Nuevo)
 		{
 			apActual->suSiguiente=apNodo;
 			apNodo->suSiguiente=apSiguiente;
 			return;
 		}
 		apActual = apSiguiente;
 	}
}

class CatalogoPiezas : private ListaPiezas
{
public:
 	void Insertar(Pieza *);
 	int Existe(int NumeroPieza);
 	Pieza * Obtener(int NumeroPieza);
 	int operator+(const CatalogoPiezas &);
 	void MostrarTodo() { Iterar(&Pieza::Desplegar); }
private:
};

void CatalogoPiezas::Insertar(Pieza * nuevaPieza)
{
 	int numeroPieza = nuevaPieza->ObtenerNumeroPieza();
 	int desplazamiento;
	if (!Encontrar(desplazamiento, numeroPieza))
 		ListaPiezas::Insertar(nuevaPieza);
 	else
 	{
 		cout << numeroPieza << " fue la ";
 		switch(desplazamiento)
 		{
 			case 0: cout << "primera "; break;
 			case 1: cout << "segunda "; break;
 			case 2: cout << "tercera "; break;
 			default: cout << desplazamiento+1 << "a "; break;
 		}
 		cout << "entrada. Rechazada!\n";
 	}
}

int CatalogoPiezas::Existe(int NumeroPieza)
{
 	int desplazamiento;
 	Encontrar(desplazamiento, NumeroPieza);
 	return desplazamiento;
}

Pieza * CatalogoPiezas::Obtener(int NumeroPieza)
{
 	int desplazamiento;
	return (Encontrar(desplazamiento,NumeroPieza));
}

int main()
{
 	CatalogoPiezas cp;
 	Pieza * apPieza = NULL;
 	int NumeroPieza;
 	int valor;
 	int opcion;
	while(1)
 	{
 		cout << "(0)Salir (1)Auto (2)Avion: ";
 		cin >> opcion;
		if(!opcion)
 			break;
 		cout << "Nuevo Numero de Pieza?: ";
 		cin >> NumeroPieza;
 		if (opcion == 1)
 		{
 			cout << "Año del modelo?: ";
 			cin >> valor;
 			apPieza = new PiezaAuto(valor,NumeroPieza);
 		}
 		else
 		{
 			cout << "Numero de Motor?: ";
 			cin >> valor;
 			apPieza = new PiezaAeroPlano(valor, NumeroPieza);
 		}
 		cp.Insertar(apPieza);
 	}
 	cp.MostrarTodo();
 	return 0;
}
Anuncios

En este caso, utilizamos el ultimo codigo y le agregamos la clase amiga. Para este ejemplo haremos a la clase NodoPieza «amiga» de la clase ListaPiezas, sustancialmente no cambia mucho, se va a agregar una nueva linea para declarar la clase amiga, y varian algunas lineas con respecto al anterior, analicemos las diferencias:

class NodoPieza
{
public:
 	friend class ListaPiezas;   // Esta es la nueva linea.
 	NodoPieza(Pieza *);
  	~NodoPieza();
  	void AsignarSiguiente(NodoPieza * nodo) { suSiguiente = nodo; }
  	NodoPieza * ObtenerSiguiente() const;
  	Pieza * ObtenerPieza() const;
private:
  	Pieza * suPieza;
  	NodoPieza * suSiguiente;
};
Anuncios

Como ven a la clase NodoPieza, solo le agregamos una linea para declararla como «amiga» de la clase ListaPiezas, ahora veremos las sutiles diferencias:

Bloque de advher03.cpp

Pieza *ListaPiezas::ObtenerPrimero() const
{
  	if (apCabeza)
 		return apCabeza->ObtenerPieza();
 	else
  		return NULL;
}

El mismo bloque en advher04.cpp:

Pieza *ListaPiezas::ObtenerPrimero() const
{
  	if (apCabeza)
 		return apCabeza->suPieza;
 	else
  		return NULL;
}
Anuncios

En este caso la diferencia va estar en la forma de obtener la informacion, en el ejemplo anterior nosotros debiamos obtenerlo mediante una funcion por no tener una relacion directa entre ambas clases, al agregarla como «amiga» nosotros le pemitimos tener acceso directo a los miembros de la misma, por eso no necesitamos ninguna funcion, observen los siguientes casos, la principal modificacion es sustancialmente cambiar las funciones que nos permitian los accesos a las partes privada de NodoPieza a las variables directas, veamos los reemplazos:

  • ObtenerSiguiente() es reemplazado por suSiguiente
  • ObtenerPieza() es reemplazado por suPieza
  • AsignarSiguiente() es reemplazado por suSiguiente
Anuncios

Como vemos en el listado todas las funciones miembros fueron reemplazadas por las llamadas a los variables miembro, todo esto gracias a la clase amiga, es decir nosotros al declarar una clase amiga podremos compartirle todas nuestras funciones y/o variables miembro sin necesitar de hacerla heredera, esto es ideal para los casos cuando necesitamos tener un conjunto de clases pero no tengan acceso publico entre ellas o no necesitemos hacer herencia o sobrecarga de funciones, ahora veremos el caso de cuando no es necesario declarar una clase como amiga sino a  algunas de sus funcionesy para ello usaremos el siguiente ejemplo:

advher05.cpp

# include <iostream>
 # include <string.h>

using namespace std;

class Cadena
{
public:
 	Cadena();
 	Cadena(const char *const);
 	Cadena(const Cadena &);
 	~Cadena();
 	char & operator[](int desplazamiento);
 	char operator[](int desplazamiento) const;
 	Cadena operator+(const Cadena &);
 	friend Cadena operator+(const Cadena &, const Cadena &);
 	void operator+=(const Cadena &);
 	Cadena & operator=(const Cadena &);
 	int ObtenerLongitud() const { return suLongitud; }
 	const char * ObtenerCadena() const { return suCadena; }
private:
 	Cadena (int);
 	char * suCadena;
 	unsigned short suLongitud;
};

Cadena::Cadena()
{
 	suCadena = new char[ 1 ];
 	suCadena[ 0 ] = '\0';
 	suLongitud = 0;
}

Cadena::Cadena(int longitud)
{
 	suCadena = new char[ longitud + 1 ];
 	for(int i = 0; i <= longitud; i++)
 		suCadena[ i ] = '\0';
 	suLongitud = longitud;
}

Cadena::Cadena (const char * const cCadena)
{
 	suLongitud = strlen(cCadena);
 	suCadena = new char[ suLongitud + 1 ];
 	for(int i = 0; i < suLongitud; i++)
 		suCadena[i] = cCadena[i];
 	suCadena[ suLongitud ] = '\0';
}

Cadena::Cadena(const Cadena & rhs)
{
 	suLongitud = rhs.ObtenerLongitud();
 	suCadena = new char[ suLongitud + 1 ];
 	for(int i = 0; i < suLongitud; i++)
 		suCadena[ i ] = rhs[ i ];
 	suCadena[ suLongitud ] = '\0';
}

Cadena::~Cadena()
{
 	delete [] suCadena;
 	suLongitud = 0;
}

Cadena& Cadena::operator=(const Cadena & rhs)
{
 	if (this == &rhs)
 		return *this;
 	delete [] suCadena;
 	suLongitud = rhs.ObtenerLongitud();
 	suCadena = new char[ suLongitud + 1 ];
 	for (int i=0; i < suLongitud; i++)
 		suCadena[ i ] = rhs[ i ];
 	suCadena[ suLongitud ] = '\0';
 	return *this;
}

char & Cadena::operator[](int desplazamiento)
{
 	if (desplazamiento > suLongitud)
 		return suCadena[ suLongitud - 1 ];
 	else
 		return suCadena[ desplazamiento ];
}

char Cadena::operator[](int desplazamiento) const
{
 	if (desplazamiento > suLongitud)
 		return suCadena[ suLongitud - 1 ];
 	else
 		return suCadena[ desplazamiento ];
}

Cadena Cadena::operator+(const Cadena & rhs)
{
 	int longitudTotal = suLongitud + rhs.ObtenerLongitud();
 	Cadena temp(longitudTotal);
 	int i,j;
	for(i = 0; i < suLongitud; i++)
 		temp[ i ] = suCadena[ i ];
 	for(j = 0, i = suLongitud; j < rhs.ObtenerLongitud(); j++, i++)
 		temp[ i ] = rhs[ j ];
 	temp[ longitudTotal ] = '\0';
 	return temp;
}

Cadena operator+(const Cadena & lhs, const Cadena & rhs)
{
 	int longitudTotal = lhs.ObtenerLongitud() + rhs.ObtenerLongitud();
 	Cadena temp(longitudTotal);
 	int i,j;
	for(i = 0; i < lhs.ObtenerLongitud(); i++)
 		temp[ i ] = lhs[ i ];
 	for(j = 0, i = lhs.ObtenerLongitud(); j < rhs.ObtenerLongitud(); j++, i++)
 		temp[ i ] = rhs[ j ];
 	temp[ longitudTotal ] = '\0';
 	return temp;
}

int main()
{
 	Cadena s1("Cadena uno ");
 	Cadena s2("Cadena dos ");
 	const char *c1 = { "C-Cadena uno " };
 	Cadena s3;
 	Cadena s4;
 	Cadena s5;
	cout << "s1: " << s1.ObtenerCadena() << endl;
 	cout << "s2: " << s2.ObtenerCadena() << endl;
 	cout << "c1: " << c1 << endl;
 	s3 = s1 + s2;
 	cout << "s3: " << s3.ObtenerCadena() << endl;
 	s4 = s1 + c1;
 	cout << "s4: " << s4.ObtenerCadena() << endl;
 	s5 = c1 + s2;
 	cout << "s5: " << s5.ObtenerCadena() << endl;
 	return 0;
}
Anuncios

En este ejemplo, veremos dos temas: funciones amigas y sobrecarga de operadores, vamos tener primero una clase llamada Cadena, donde definiremos la funcion miembro «amiga» y el resto de los prototipos para nuestras funciones y operadores, veamos el bloque de la clase:

class Cadena
 {
 public:
      Cadena();
      Cadena(const char *const);
      Cadena(const Cadena &);
      ~Cadena();
      char & operator[](int desplazamiento);
      char operator[](int desplazamiento) const;
      Cadena operator+(const Cadena &);
      friend Cadena operator+(const Cadena &, const Cadena &);
      void operator+=(const Cadena &);
      Cadena & operator=(const Cadena &);
      int ObtenerLongitud() const { return suLongitud; }
      const char * ObtenerCadena() const { return suCadena; }
 private:
      Cadena (int);
      char * suCadena;
      unsigned short suLongitud;
 };
Anuncios

Como pueden ver en este bloque resalte la linea encargada de declarar nuestro operador de signo mas (+), esta tambien va a ser la encargada de efectuar la union de dos cadenas tipo C, en el resto iremos definiendo los prototipos creados en la clase, en los siguientes bloques se definen a los prototipos de la clase Cadena, todos trabajan de forma muy similar a como lo hicimos antes, veamos a la funcion que hicimos amiga:

Cadena operator+(const Cadena & lhs, const Cadena & rhs)
{
 	int longitudTotal = lhs.ObtenerLongitud() + rhs.ObtenerLongitud();
 	Cadena temp(longitudTotal);
 	int i,j;
	for(i = 0; i < lhs.ObtenerLongitud(); i++)
 		temp[ i ] = lhs[ i ];
 	for(j = 0, i = lhs.ObtenerLongitud(); j < rhs.ObtenerLongitud(); j++, i++)
 		temp[ i ] = rhs[ j ];
 	temp[ longitudTotal ] = '\0';
 	return temp;
}
Anuncios

Este operador es el encargado de sumar dos cadenas del tipo C, en este caso tendremos dos tipos Cadena, lhs y rhs, volvemos a crear longitudTotal pero ahora sera la suma total de los tamaños de lhs y rhs, esta funcion a diferencia del operador anterior y en vez de sumar rhs a suCadena, esta sumara dos cadenas distintas, esto es gracias a que fue definida como amiga dentro de la declaracion de la clase, y por ende no necesita otro prototipo y como se ve tiene acceso a las dos cadenas a traves de sus metodos de acceso publico, en el resto del programa, solamente nos encargamos de crear unos objetos de tipo cadena y proceder con la salida y ejecutar los operadores necesarios, compilemos y veamos como es la salida de ejemplo:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./advher05
s1: Cadena uno
s2: Cadena dos
c1: C-Cadena uno
s3: Cadena uno Cadena dos
s4: Cadena uno C-Cadena uno
s5: C-Cadena uno Cadena dos
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Hasta aqui hemos visto como definir una funcion amiga con una sobrecarga de operadores donde nos permite sumar dos cadenas de tipo C, pero todavia se sigue viendo de forma fea, es decir para obtener nuestro resultado debemos hacer esto:

cout << «s5: » << s5.ObtenerCadena() << endl;

en el siguiente ejemplo, transformaremos eso en esto:

cout << «s5: » << s5 << endl;

Anuncios

Tomemmos el ejemplo anterior y le haremos unas sutiles modificaciones, veamos el codigo:

advher06.cpp

# include <iostream>
# include <string.h>

using namespace std;

class Cadena
{
public:
 	Cadena();
 	Cadena(const char *const);
 	Cadena(const Cadena &);
 	~Cadena();
 	char & operator[](int desplazamiento);
 	char operator[](int desplazamiento) const;
 	Cadena operator+(const Cadena &);
 	void operator+=(const Cadena &);
 	Cadena & operator=(const Cadena &);
 	friend ostream & operator<< (ostream & elFlujo, Cadena & laCadena);
 	int ObtenerLongitud() const { return suLongitud; }
 	const char * ObtenerCadena() const { return suCadena; }
private:
 	Cadena (int);
 	char * suCadena;
 	unsigned short suLongitud;
};

Cadena::Cadena()
{
 	suCadena = new char[ 1 ];
 	suCadena[ 0 ] = '\0';
 	suLongitud = 0;
}

Cadena::Cadena(int longitud)
{
 	suCadena = new char[ longitud + 1 ];
 	for(int i = 0; i <= longitud; i++)
 		suCadena[ i ] = '\0';
 	suLongitud = longitud;
}

Cadena::Cadena (const char * const cCadena)
{
 	suLongitud = strlen(cCadena);
 	suCadena = new char[ suLongitud + 1 ];
 	for(int i = 0; i < suLongitud; i++)
 		suCadena[i] = cCadena[i];
 	suCadena[ suLongitud ] = '\0';
}

Cadena::Cadena(const Cadena & rhs)
{
 	suLongitud = rhs.ObtenerLongitud();
 	suCadena = new char[ suLongitud + 1 ];
 	for(int i = 0; i < suLongitud; i++)
 		suCadena[ i ] = rhs[ i ];
 	suCadena[ suLongitud ] = '\0';
}

Cadena::~Cadena()
{
 	delete [] suCadena;
 	suLongitud = 0;
}

Cadena& Cadena::operator=(const Cadena & rhs)
{
 	if (this == &rhs)
 		return *this;
 	delete [] suCadena;
 	suLongitud = rhs.ObtenerLongitud();
 	suCadena = new char[ suLongitud + 1 ];
 	for (int i=0; i < suLongitud; i++)
 		suCadena[ i ] = rhs[ i ];
 	suCadena[ suLongitud ] = '\0';
 	return *this;
}

char & Cadena::operator[](int desplazamiento)
{
 	if (desplazamiento > suLongitud)
 		return suCadena[ suLongitud - 1 ];
 	else
 		return suCadena[ desplazamiento ];
}

char Cadena::operator[](int desplazamiento) const
{
 	if (desplazamiento > suLongitud)
 		return suCadena[ suLongitud - 1 ];
 	else
 		return suCadena[ desplazamiento ];
}

Cadena Cadena::operator+(const Cadena & rhs)
{
 	int longitudTotal = suLongitud + rhs.ObtenerLongitud();
 	Cadena temp(longitudTotal);
 	int i,j;
	for(i = 0; i < suLongitud; i++)
 		temp[ i ] = suCadena[ i ];
 	for(j = 0, i = suLongitud; j < rhs.ObtenerLongitud(); j++, i++)
 		temp[ i ] = rhs[ j ];
 	temp[ longitudTotal ] = '\0';
 	return temp;
}

void Cadena::operator+=(const Cadena & rhs)
{
 	unsigned short rhsLong = rhs.ObtenerLongitud();
 	int longitudTotal = suLongitud + rhsLong;
 	Cadena temp(longitudTotal);
 	int i,j;
	for(i = 0; i < suLongitud; i++)
 		temp[ i ] = suCadena[ i ];
 	for(j = 0, i = 0; j < rhs.ObtenerLongitud(); j++, i++)
 		temp[ i ] = rhs[ i - suLongitud ];
 	temp[ longitudTotal ] = '\0';
 	*this = temp;
}

ostream & operator << (ostream & elFlujo, Cadena & laCadena)
{
 	elFlujo << laCadena.suCadena;
 	return elFlujo;
}

int main()
{
 	Cadena laCadena("Hola, Mundo!!");
 	cout << laCadena;
 	cout << endl;
 	return 0;
}
Anuncios

Como dijimos es el codigo anterior con sutiles diferencias, veamos la clase modificada:

class Cadena
 {
 public:
      Cadena();
      Cadena(const char *const);
      Cadena(const Cadena &);
      ~Cadena();
      char & operator[](int desplazamiento);
      char operator[](int desplazamiento) const;
      Cadena operator+(const Cadena &);
      void operator+=(const Cadena &);
      Cadena & operator=(const Cadena &);
      friend ostream & operator<< (ostream & elFlujo, Cadena & laCadena);
      int ObtenerLongitud() const { return suLongitud; }
      const char * ObtenerCadena() const { return suCadena; }
 private:
      Cadena (int);
      char * suCadena;
      unsigned short suLongitud;
 };

Como ven, en este caso desaparecio la funcion amiga anterior:

friend Cadena operator+(const Cadena &, const Cadena &);

Y esta fue reemplazada por esta linea:

friend ostream & operator<< (ostream & elFlujo, Cadena & laCadena);
Anuncios

Esta se encarga de redefinir al operador <<, luego el resto de los bloques trabajan de la misma forma al anterior ejemplo, solamente hay dos bloques distintos al anterior ejemplo los cuales explicaremos ahora, el primero es este:

void Cadena::operator+=(const Cadena & rhs)
{
 	unsigned short rhsLong = rhs.ObtenerLongitud();
 	int longitudTotal = suLongitud + rhsLong;
 	Cadena temp(longitudTotal);
 	int i,j;
	for(i = 0; i < suLongitud; i++)
 		temp[ i ] = suCadena[ i ];
 	for(j = 0, i = 0; j < rhs.ObtenerLongitud(); j++, i++)
 		temp[ i ] = rhs[ i - suLongitud ];
 	temp[ longitudTotal ] = '\0';
 	*this = temp;
}
Anuncios

Este bloque es similar al bloque operador mas (+) del ejemplo anterior pero en este caso no devuelve ningun valor sino simplemente asigna ese valor al apuntador this, en el proximo bloque veremos la redefinicion del operador <<:

ostream & operator << (ostream & elFlujo, Cadena & laCadena)
{
 	elFlujo << laCadena.suCadena;
 	return elFlujo;
}
Anuncios

Como vemos en este caso usamos un objeto del tipo ostream, al cual lo veremos en mas detalle en el proximo post, aca basicamente se encarga de devolvernos el resultado de la sobrecarga efectuada al operador << por medio de la funcion asignada, el resultado es este:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./advher06
Hola, Mundo!!
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Con esto terminamos herencia avanzada, hemos visto contencion, delegacion, implementacion en base a, herencia privada, clases amigas y funciones amigas con sobrecarga de operadores. La herencia publica es buena cuando los objetos derivados son de la misma clase base pero en cambio si necesitamos restringir el acceso total utilizaremos la herencia privada, la contencion es buena cuando debemos derivar funcionalidad sin permitir acceso a los miembros protegidos, la clase amiga es buena para cuando tenemos dos clases donde intercambian informacion frecuentemente pero sin tener que ser derivadas una de la otra, y por ultimo las funciones amigas, las cuales implementaremos cuando nosotros deseamos permitir el acceso a una funcion miembro sin tener que permitir el acceso a todos los miembros de la clase. Espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.50

Anuncio publicitario