Te comento un poco lo que puedo ver de tu código:
Clases confusas
anidar una clase dentro de otra puede tener sentido en ciertas ocasiones (para organizar datos para uso interno de la clase, por ejemplo. No es tu caso.
Además, estás creando dentro de
Trab el arreglo de trabajadores... el concepto es algo complicado porque estás mezclando responsabilidades. Tendrías un código más limpio si:
- Trab la declaras fuera de Empresa
- Trab se "centra" en almacenar los datos de un trabajador
- Empresa pasa a gestionar la lista de trabajadores
Algo así:
Código C++:
Ver originalclass Trabajador
{
public:
Trabajador( )
: _numEmpleado( 0 ),
_cedula( 0 ),
_antiguedad( 0 ),
_salario( 0 )
{ }
int NumEmpleado( ) const
{ return _numEmpleado; }
void SetNumEmpleado( int num )
{ _numEmpleado = num; }
int Cedula( ) const
{ return _cedula; }
void SetCedula( int cedula )
{ _cedula = cedula; }
int Antiguedad( ) const
{ return _antiguedad; }
void SetAntiguedad( int antiguedad )
{ _antiguedad = antiguedad; }
string Nombre( ) const
{ return _nombre; }
void SetNombre( const string& nombre )
{ _nombre = nombre; }
string Nombre2( ) const
{ return _nombre2; }
void SetNombre2( const string& nombre )
{ _nombre2 = nombre; }
string Nacionalidad( ) const
{ return _nacionalidad; }
void SetNacionalidad( const string& nacionalidad )
{ _nacionalidad = nacionalidad; }
double Salario( ) const
{ return _salario; }
void SetSalario( double salario )
{ _salario = salario; }
private:
int _numEmpleado;
int _cedula;
int _antiguedad;
string _nombre;
string _nombre2;
double _salario;
};
class Empresa
{
private:
std::vector< Empleado > _empleados;
}
Aunque a primera vista parezca que hay más código este diseño tiene bastantes ventajas frente al actual:
- Cada clase se dedica a una única cosa, los posibles errores están más acotados
- Como para modificar cada valor de Trabajador hay que llamar a un método, es muy sencillo añadir filtros para evitar la inserción de valores no válidos
- Ampliar la funcionalidad es más sencillo
También habrás notado que he sustituído los
char* por la clase
string.
string es una clase de C++ pensada para trabajar con cadenas de texto. Es muy util y da muchos menos problemas que trabajar con arreglos de tipo char.
Seguimos separando responsabilidades
Yo entiendo que puede parecer muy práctico porque parece que se escribe menos código, pero tener en la clase
Empresa una función que sea
Anadir_Empl que interactua con la entrada salida no es una buena idea:
- Genera acoplamiento, si en el futuro los datos pasan a venir de un socket, de una base de datos, de un USB... tendrás que modificar la clase Empresa y después tendrás que probar esta clase al completo para asegurarte de que todo funciona bien.
- En línea con lo anterior, si resulta que después tienes que compatibilizar dos o más orígenes de datos la única solución que te queda es duplicar código mientras la clase empieza a almacenar código sin control.
- En la poca historia que lleva la programación a sus espaldas ha quedado claro que los diseños monolíticos (como es tu caso) son la peor elección posible.
Si se piensa un poco, se ve que la responsabilidad de
Empresa es almacenar la lista de trabajadores. Al menos en tu código no hay más elementos que la Empresa deba almacenar. Con esto en mente la clase Empresa puede quedar de dos formas diferentes:
Código C++:
Ver original// Como un alias de un vector
typedef std::vector< Trabajador > Empresa;
// Como una clase propia que almacene un vector de trabajadores
class Empresa
{
private:
std::vector< Trabajador > _trabajadores;
};
Como imagino que tampoco te apetece meterte en un jardín, yo tiraría de momento por la primera opción. Mientras no tengas que añadir más tipos de objetos a
Empresa te puedes ahorrar bastante código así.
Espera, ¿y qué pasa entonces con las funciones que actualmente hay en
Empresa? Bueno, es que ninguna de esas funciones debería haber pertenecido nunca a esa clase. Lo mejor es que las dejes como funciones independientes y, si en el futuro ves que se pueden agrupar en clases, entonces dedicas un tiempo a refactorizar el código.
Cuidado con las llamadas a las funciones
Código C++:
Ver originalfloat Empresa::Carga_Inicial() {
int N;
cout<<"Carga Inicial De Empleados"<<endl;
cout<<"---------------------------"<<endl;
cout<<"Ingrese la cantidad de Empleados que desea Ingresar:"<<endl;
cin>>N;
while((N < 2) || (N > 100)) {
cout<<"Debe ingresar un numero mayor o igual a 0 y menor o igual 100"<<endl;
cin>>N;
}
int i;
for (i = 0; i < N; i++) {
cout<<"Registro numero:"<<i+1<<endl;
Empresa::Anadir_Empl(); // <<<-- AQUI!!!!!!
}
}
La línea que te marco está intentando hacer una llamada a una función estática. Mucho cuidado con eso porque la aplicación puede funcionar incorrectamente.
No se si te lo han explicado, pero cualquier método
no estático de una clase o estructura en C++ tiene una variable local creada por defecto. La variable en cuestión es un puntero a la clase actual y se llama
this. Otra característica de esta variable es que es implícita, es decir, el compilador es capaz de intuir su uso.
¿Por qué te cuento este royo? Pues porque en el ejemplo que te he puesto, dispones de dos formas de realizar la llamada a la función:
Código C++:
Ver originalfor (i = 0; i < N; i++) {
cout<<"Registro numero:"<<i+1<<endl;
// opción 1
this->Anadir_Empl();
// opción 2
Anadir_Empl();
}
Y tu podrás pensar... Pues vaya chorrada que exista el puntero this si luego no hace falta usarlo... Bueno, this tiene su utilidad en ciertos casos... por ejemplo imagínate que tienes una colección de objetos de tipo Teléfono y que cuando se descuelga uno debe avisar a un objeto de tipo Centralita para poder dar tono. Queda claro que la centralita necesita un puntero al teléfono que se ha descolgado para poder comunicarse con el. La cosa podría quedar así:
Código C++:
Ver originalclass Telefono
{
void Descolgar( )
{
// Le pedimos tono a la centralita... y le indicamos quiénes somos
Centralita::PeticionTono( this );
}
};
class Centralita
{
public:
static void PeticionTono( Telefono* telefono );
};
Otro caso en el que necesitas usar "this":
Código C++:
Ver originalclass A
{
public:
void SetDato( int dato )
{
// ¿Se te ocurre una forma alternativa de almacenar el valor cuando las dos
// variables se llaman igual?
this->dato = dato;
}
private:
int dato;
};
Cuidado con los return
Todas las funciones de Empresa, salvo una, indican en su declaración que devuelven un float... ¿cuántas tienen un return? pues eso. Si una función debe retornar un valor hay que poner un return.
Dicho esto te indico que se entiende como una falta de respeto que nos cueles código que no compila. Salvo que tu problema esté relacionado precisamente con el hecho de que no eres capaz de hacerlo compilar preocúpate por poner código compilable.
Eliminar elementos de una lista
Si la lista se basa en un arreglo, tienes que mover una posición los elementos que sean posteriores al elemento a eliminar para ocupar el hueco que va a dejar el elemento eliminado:
Código C++:
Ver originalNumElementos--;
for( int i=posElementoAEliminar; i<NumElementos; ++i)
{
lista[i] = lista[i+1];
}
Si la lista se basa en un contenedor de C++ basta con que le indiques al contenedor el elemento que quieres eliminar y él se encarga de todo:
Código C++:
Ver originalstd::vector< int > elementos;
elementos.push_back( 1 );
elementos.push_back( 2 );
elementos.push_back( 3 );
// Se elimina el segundo elemento
elementos.erase( elementos.begin( ) + 1 );
for( int i=0; i < elementos.size( ); ++i )
std::cout << elementos[ i ] << std::endl;
Un saludo