Hola, a todos sean bienvenidos a mi nuevo post. Hoy continuaremos con lo iniciado en el post anterior, ahora 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 y luego lo explicamos

advher4.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;
}

Este el ultimo ejemplo visto en el post anterior, con la salvedad de ahora convertir 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:

Ejemplo Anterior:

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;
};

Ejemplo actual:

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:
};

En este caso es la declaracion de la clase CatalogoPiezas, en el ejemplo anterior lo mas notorio son 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:

Ejemplo anterior:

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”;
}
}

Ejemplo actual:

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”;
}
}

Observen el ejemplo anterior, en ese caso 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:

Ejemplo anterior:

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

Ejemplo actual:

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

Como pueden ver, otra vez tenemos el mismo caso en lugar de utilizar a traves del objeto creado de ListaPiezas para poder acceder a las funciones miembro pero ahora al ser derivado de esta, no es necesario. Veamos el ultimo bloque:

Ejemplo anterior:

Pieza * CatalogoPiezas::Obtener(int NumeroPieza)
{
int desplazamiento;

Pieza * laPieza = laListaPiezas.Encontrar(desplazamiento,NumeroPieza);
return laPieza;
}

Ejemplo actual:

Pieza * CatalogoPiezas::Obtener(int NumeroPieza)
{
int desplazamiento;

return (Encontrar(desplazamiento,NumeroPieza));
}

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:

$ ./program/advher4
(0)Salir (1)Auto (2)Avion: 1
Nuevo Numero de Pieza?: 11011
Año del modelo?: 10
(0)Salir (1)Auto (2)Avion: 2
Nuevo Numero de Pieza?: 22022
Numero de Motor?: 10
(0)Salir (1)Auto (2)Avion: 1
Nuevo Numero de Pieza?: 22022
Año del modelo?: 94
22022 fue la segunda entrada. Rechazada!
(0)Salir (1)Auto (2)Avion: 1
Nuevo Numero de Pieza?: 33033
Año del modelo?: 11
(0)Salir (1)Auto (2)Avion: 2
Nuevo Numero de Pieza?: 44044
Numero de Motor?: 11
(0)Salir (1)Auto (2)Avion: 1
Nuevo Numero de Pieza?: 44044
Año del modelo?: 11
44044 fue la 4a entrada. Rechazada!
(0)Salir (1)Auto (2)Avion: 0

Numero de Pieza: 11011
Año del modelo: 10

Numero de Pieza: 22022
Motor Numero: 10

Numero de Pieza: 33033
Año del modelo: 11

Numero de Pieza: 44044
Motor Numero: 11

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. El siguiente tipo de herencia es llamada Clases amigas, veamos el siguiente ejemplo:

advher5.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->suPieza->*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;
}

En este caso, utilizamos el ultimo codigo y le agregamos las clases amigas, o mejor dicho 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;
};

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

Ejemplo anterior:

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

Ejemplo actual:

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

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:

Ejemplo anterior:

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;
}
}

Ejemplo actual:

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->suPieza->*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;
}
}

En este caso les muestro todas las lineas donde se reemplazaron las funciones miembros anteriores 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 funciones, veamoslo a traves del siguiente ejemplo:

advher6.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;
}

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;
};

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, veamos los bloques:

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

Este es nuestro constructor predeterminado, el siguiente bloque:

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

Este es el constructor privado, el cual se encargara de crear una variable del tamaño requerido por los metodos, la misma se completara con valores nulos, pasemos al siguiente:

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’;
}

Este se encarga de convertir un array de caracteres (char) en cadena, proximo bloque:

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’;
}

Este es el constructor de copia, bloque siguiente:

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

Este es el destructor, se encarga de liberar la memoria. Analicemos el siguiente bloque:

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;
}

Este es el operador de igual (=), chequea si el apuntador this es igual a rhs, en caso afirmativo devuelve el valor del apuntador this, en caso contrario, elimina el valor almacenado en suCadena y procede a rellenarlo con el contenido de rhs, siguiente bloque:

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

En este bloque crearemos el operador de desplazamiento no constante, este bloque regresa la referencia a un caracter para poder cambiarlo, proximo bloque:

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

Es igual al bloque anterior pero para elementos constantes, siguiente bloque:

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;
}

Este bloque se encarga de agregar el valor de rhs al valor de suCadena, esto lo hace primero creando una longitud total (longitudTotal), el cual es el producto de la suma de los valores de suLongitud mas el tamaño de rhs, luego creamos un objeto llamado temp con el tamaño de longitudTotal, luego con el primer bucle for, llenaremos al objeto temp con el contenido de suCadena, en el segundo bucle for seguiremos llenando el valor de temp con el de rhs, luego cerramos a temp, para tener validez, y por ultimo regresamos el valor de temp, el proximo bloque es el definido como 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;
}

Este operador es la encargada 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, despues es exactamente igual al bloque anterior pero 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, les muestro la salida:

$ ./program/advher6
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

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;

Pasemos a ver el siguiente ejemplo:

advher7.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;
}

Este ejemplo, es similar al ejemplo anterior pero varian un par de segmentos los cuales pasaremos a detallar, el primero va a ser la clase Cadena:

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 fue reemplazada por esta linea, friend ostream & operator<< (ostream & elFlujo, Cadena & laCadena);, 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;
}

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;
}

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:

$ ./program/advher7
Hola, Mundo!!

Con esto terminamos herencia avanzada, hemos visto contencion, delegacion, implementacion en base a, herencia privada, clases amigas, 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 bueno cuando debemos derivar funcionalidad sin permitir acceso a los miembros protegidos, la clase amiga es bueno 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, nos vemos en el proximo post.

Anuncios