/*
* GNU/C++ Implementación de una lista enlazada para objetos Pieza
*
* Ejemplo un poco modificado del libro "Aprendiendo C++ para Linux"
*
* Probado con g++-4.0 sobre GNU/Debian
*/
#include <iostream>
/*
* Notese que la biblioteca estándar de C++ se encuentra definica dentro del
* espacio de nombres std, de ahi que en todos los programas se utiliza dicho
* espacio de nombres mediante la notacion implicita (using namespace std;)
*/
using namespace std;
// ********** Pieza **********
// clase abstracta de piezas
class Pieza
{
public:
//constructores
Pieza(): suNumeroPieza(1) {}
Pieza(int NumeroPieza): suNumeroPieza(NumeroPieza) {}
//destructor
//Si hay alguna funcion en la clase virtual, es recomendable colocar
// el destructor como virtual. Si hay un apuntador a una clase derivada
// (Pieza * apPieza=new clase_Derivada;) al destruir la misma (delete
// apPieza), invocara automaticamente al destructor de la clase base.
virtual ~Pieza() {}
//funciones
int ObtenerNumeroPieza() const { return suNumeroPieza; }
//Funcion virtual pura. Un función virtual se convierte en pura
// inicializandola a 0. Cualquier clase que tenga una o varias funciones
// virtuales puras, es un ADT (Abstract Data Types) y es ilegal
// instanciar un objeto de una clase que sea ADT. Al colocar una funcion
// virtual pura, se esta indicando a los clientes de la clase: 1-No
// crear un objeto de la clase, hacer derivaciones de ella. 2-
// Asegurarse de redefinir la funcion virtual pura.
virtual void Desplegar() const=0;
private:
int suNumeroPieza;
};
//implementación de la funcion virtual pura para que las clases derivadas puedan
// encadenarse
void Pieza::Desplegar() const
{
cout << "\nNúmero de Pieza: " << suNumeroPieza << endl;
}
// ********** Pieza de Auto **********
//
class PiezaAuto: public Pieza
{
public:
//constructores
PiezaAuto(): suAnioModelo(94) {}
PiezaAuto(int anio, int numeroPieza): suAnioModelo(anio),Pieza(numeroPieza) {}
//funciones
virtual void Desplegar() const
{
Pieza::Desplegar();
cout << "Año del modelo: " << suAnioModelo << endl;
}
private:
int suAnioModelo;
};
// ********** Pieza de AeroPlano **********
//
class PiezaAeroPlano: public Pieza
{
public:
//constructores
PiezaAeroPlano(): suNumeroMotor(1) {}
PiezaAeroPlano(int numeroMotor, int numeroPieza): suNumeroMotor(numeroMotor),Pieza(numeroPieza) {}
//funciones
virtual void Desplegar() const
{
Pieza::Desplegar();
cout << "Motor número: " << suNumeroMotor << endl;
}
private:
int suNumeroMotor;
};
// ********** Nodo de Pieza **********
//Sirve como interfaz entre la clase Pieza y la clase ListaPiezas
//Contiene un apuntador a una pieza y un apuntador al siguiente nodo de la lista
class NodoPieza
{
public:
//constructor
NodoPieza(Pieza * apPieza): suPieza(apPieza),suSiguiente(0) {}
//destructor
~NodoPieza();
//funciones
void AsignarSiguiente(NodoPieza * nodo)
{
suSiguiente=nodo;
}
NodoPieza * ObtenerSiguiente() const
{
//regresa null si no hay siguiente NodoPieza
return suSiguiente;
}
Pieza * ObtenerPieza() const;
private:
Pieza * suPieza;
NodoPieza * suSiguiente;
};
NodoPieza::~NodoPieza()
{
delete suPieza;
suPieza=0;
delete suSiguiente;
suSiguiente=0;
}
Pieza * NodoPieza::ObtenerPieza() const
{
if(suPieza)
return suPieza;
else
return NULL; //error
}
// ********** lista de Piezas **********
//Mantiene un apuntador al primer elemento de la lista (apCabeza) y lo utiliza
// para tener acceso a los demas metodos al avanzar por la lista
class ListaPiezas
{
public:
//constructor
ListaPiezas(): apCabeza(0), suCuenta(0) {}
//destructor
~ListaPiezas() { delete apCabeza; }
//funciones
Pieza * Encontrar(int & posicion, int NumeroPieza) const;
int ObtenerCuenta () const { return suCuenta; }
Pieza * ObtenerPrimero() const;
//Regresa una referencia a una variable miembro estatica
static ListaPiezas & ObtenerListaPiezasGlobal() { return ListaPiezasGlobal; }
void Insertar(Pieza *);
void Iterar(void (Pieza::*func)() const) const;
//operadores
Pieza * operator[](int) const;
private:
//maniente un apuntador al primer elemento del NodoPieza
NodoPieza * apCabeza;
//mantiene el valor total de elementos que hay en la lista
int suCuenta;
static ListaPiezas ListaPiezasGlobal;
};
//Inicializamos la variable statica ListaPiezasGlobal. Esto, es porque una
// variable miembro estatica no la define, deve hacerse desde fuera de la
// declaración de la clase.
ListaPiezas ListaPiezas::ListaPiezasGlobal;
//Busca la pieza correspondiente a NumeroPieza, si la encuentra, devuelve un
// apuntador a la misma, y posicion obtiene la posición del elemento en la
// lista, ya que posicion se pasa por refercia, todas las modificaciones
// dentro de la función tendran valor al finalizar la misma.
Pieza * ListaPiezas::Encontrar (int & posicion, int NumeroPieza) const
{
NodoPieza * apNodo=NULL;
for(apNodo=apCabeza,posicion=0;apNodo!=NULL;apNodo=apNodo->ObtenerSiguiente(),posicion++)
{
//apNodo->ObtenerPieza, devuelve un apuntador a Pieza, por lo que
// podemos utilizar la funcion de la clase Pieza->ObtenerNumeroPieza()
if(apNodo->ObtenerPieza()->ObtenerNumeroPieza()==NumeroPieza)
break;
}
if(apNodo==NULL)
return NULL;
else
return apNodo->ObtenerPieza();
}
//Devuelve un apuntador al primer elemento de la lista. Regresa NULL si la lista
// esta vacia
Pieza * ListaPiezas::ObtenerPrimero() const
{
if(apCabeza)
return apCabeza->ObtenerPieza();
else
return NULL;
}
//Crea un NodoPieza para este nuevo objeto (Pieza), y agrega la Pieza a la
// lista, ordenada por NumeroPieza
void ListaPiezas::Insertar(Pieza * apPieza)
{
NodoPieza * apNodo=new NodoPieza(apPieza);
NodoPieza * apActual=apCabeza;
NodoPieza * apSiguiente=NULL;
int Nuevo=apPieza->ObtenerNumeroPieza();
int Siguiente=0;
suCuenta++;
//si apCabeza, no tiene valor, quiere decir que es el primer objeto de la
// lista.
if(!apCabeza)
{
apCabeza=apNodo;
return;
}
//si este es mas pequeño que el nodo cabeza, este se convierte en el nuevo
// nodo cabeza
if(apCabeza->ObtenerPieza()->ObtenerNumeroPieza()>Nuevo)
{
apNodo->AsignarSiguiente(apCabeza);
apCabeza=apNodo;
return;
}
for(;;)
{
//si no hay siguiente, agregar este
if(!apActual->ObtenerSiguiente())
{
apActual->AsignarSiguiente(apNodo);
return;
}
//si va despues de este y antes del siguiente, entonces insertarlo aqui,
// de no ser asi, obtener el siguiente
apSiguiente=apActual->ObtenerSiguiente();
Siguiente=apSiguiente->ObtenerPieza()->ObtenerNumeroPieza();
if(Siguiente>Nuevo)
{
apActual->AsignarSiguiente(apNodo);
apNodo->AsignarSiguiente(apSiguiente);
return;
}
apActual=apSiguiente;
}
}
//Muestra el listado de Piezas utilizando la función Desplegar de PiezaAuto o
// PiezaAeroPlano.
//Recibe un apuntador a una funcion miembro (Desplegar) de Pieza la cual no
// recibe parametros, regresa void y es const.
void ListaPiezas::Iterar(void (Pieza::*func)() const) const
{
if(!apCabeza)
return;
NodoPieza * apNodo=apCabeza;
do
(apNodo->ObtenerPieza()->*func)();
while (apNodo=apNodo->ObtenerSiguiente());
}
//Permite un acceso directo al objeto Pieza
Pieza * ListaPiezas::operator[](int desFase) const
{
NodoPieza * apNodo=apCabeza;
if(!apCabeza)
return NULL; //no hay ningun valor
if(desFase>suCuenta)
return NULL; //si el valor recibido es mayor que el total de elementos
//recorremos los nodos hasta llegar a la posicion desFase
for(int i=0;i<desFase;i++)
apNodo=apNodo->ObtenerSiguiente();
return apNodo->ObtenerPieza();
}
int main()
{
//se declara una referencia a ListaPiezas y se inicializa con el valor
// de ListaPiezasGlobal
ListaPiezas & lp=ListaPiezas::ObtenerListaPiezasGlobal();
Pieza * apPieza=NULL;
int NumeroPieza;
int valor;
int opcion;
//bucle hasta el infinito. Se finaliza desde el interior del mismo.
while(1)
{
cout << "(0)Salir (1)Auto (2)Avion: ";
cin >> opcion;
if(!opcion)
break;
cout << "¿Nuevo NumeroPieza?: ";
cin >> NumeroPieza;
if(opcion==1)
{
cout << "¿Año del modelo? ";
cin >> valor;
apPieza=new PiezaAuto(valor,NumeroPieza);
}else{
cout << "¿Número del motor? ";
cin >> valor;
apPieza=new PiezaAeroPlano(valor,NumeroPieza);
}
//insertamos la pieza en la lista
lp.Insertar(apPieza);
}
void (Pieza::*apFunc)()const=&Pieza::Desplegar;
lp.Iterar(apFunc);
return 0;
}
Comentarios sobre la versión: Versión 1 (0)
No hay comentarios