Ejercicios de Clases
Sitio: | Facultad de Ingeniería U.Na.M. |
Curso: | Computación ET-344 |
Libro: | Ejercicios de Clases |
Imprimido por: | Invitado |
Día: | miércoles, 22 de enero de 2025, 14:01 |
1. Ejercicios Propuestos
Ejercicio 1:
Crear una Clase Televisor con propiedades privada de estado ( on/off) y
de Valores de Canal y Volumen. Crear métodos públicos para encender,
apagar , cambiar de canal y de volumen. Luego desde main crear un menú
que permita manejar un objeto tv14p.-
Ejercicio 2:
Crear una clase empleado que contenga como propiedades privadas: el
nombre, dirección y sueldo . Como métodos públicos poner y obtener para
cada uno de sus propiedades y LeerDatos() y VerDatos que leen datos del
teclado y lo visualizan en pantalla respectivamente.
Ejercicio 3:
Escribir una Clase Pila de Reales con funciones miembro para poner un
elemento y sacar un elemento de la pila. La pila debería ser del tipo
LIFO ( ultimo en Entrar es el primero en Salir). Como métodos publicos
se usarán poner que añade un elemento a la pila y sacar que borra un
elemento de la pila. Tomar como tamaño maximo de pila un valor de 10 con
#define.
Ejercicio 4:
Crear una clase llamada hora que tenga miembros separados de tipo int
para horas, minutos, segundos. Un constructor inicializará este dato a o
y otro lo inicializará a valores fijos ( ej : 12:00:00). Un método
deberá visualizar la hora en formato : hh:mm:ss . Otro método sumará dos
objetos de tipo hora pasados como argumentos. Desde main se crean dos
objetos inicializados y otro sin inicializar. Sumar los valores
inicializados y poner el resultado en el no inicializado. Por último
visualizar el valor resultante.
Ejercicio 5:
Cree una clase Rectangulo con los atributos longitud y ancho, cada uno con un valor predeterminado igual a 1.
Proporcione métodos (funciones miembro) que calculen el perímetro y el área del rectángulo.
Además proporcione métodos establecer y obtener (leer) para los
atributos longitud y ancho, que permitan establecer los valores y leer
los valores respectivamente. La función establecer debe verificar que
longitud y ancho contengan números de punto flotante mayores que 0.0 y
menores que 20.0.
Ejercicio 6:
Cree una clase llamada Complejo para realizar aritmética con números complejos. Escriba un programa para usar su clase.
(Recordar que los números complejos tienen la forma: parteReal + parteImaginaria*i
donde i es la raíz cuadrada de -1)
Utilice variables double para representar datos de tipo private de una
clase. Proporcione un constructor que permita inicializar un objeto de
esta clase cuando se declare. El constructor debe contener valores
predeterminados en caso de que no se proporcionen inicializadotes.
Proporcione funciones miembro tipo public para realizar lo siguiente:
a)Suma de dos números complejos (las partes reales se suman juntas y las imaginarias se suman juntas)
b)Resta de dos números Complejos (idem ant pero restando)
c)Impresión de números complejos de la forma (a, b) donde a es la parte real y b es la parte imaginaria.
Ejercicio 7:
Escribir un código que tenga una clase de nombre fecha, esta deberá
tener un constructor que inicialice una propiedad hoy con la fecha
actual y un par de métodos que permitan:
Si se pasan dos fechas en formato dd mm aa dd mm aa , devuelve la cantidad de días entre esas dos fechas.
Si se pasan una fecha en formato dd mm aa, dice la cantidad de años, meses días desde esa fecha a la de hoy.-
Desde main se presentará un menú que permita elegir alguna de las opciones.
A modo de aclaración , los años biciestros son aquellos que son divisibles por 400 o por 4 y no por 100.
Ejercicio 8:
Escribir una Clase Pila de Reales con funciones miembro para poner un
elemento y sacar un elemento de la pila. La pila debería ser del tipo
FIFO ( primero en Entrar es el primero en Salir). Como métodos publicos
se usarán poner que añade un elemento a la pila y sacar que borra un
elemento de la pila. Tomar como tamaño maximo de pila de manera dinámica
en tiempo de ejecución.
Ejercicio 9:
Escribir una Clase que permita cargar y crear una lista enlazada simple.
Buscar que el /los puntero/s y la o las variables ( estructuras , etc)
sea privados.-
Ejercicio 10:
Escribir una Clase que permita cargar y crear una lista enlazada doble.
Buscar que el /los puntero/s y la o las variables ( estructuras , etc)
sea privados.-
2. Constructor Copia (informativo)
Constructor copia
Un constructor de este tipo crea un objeto a partir de otro objeto existente. Estos constructores sólo tienen un argumento, que es una referencia a un objeto de su misma clase.
El constructor de copia, como su nombre indica, se usa para copiar los
datos de un objeto a otro objeto (del mismo tipo) que se esté
construyendo . Conceptualmente el objeto en construcción no tiene ningún motivo para
modificar el objeto que está copiando, por eso el parámetro recibido
suele ser constante, aunque el estándar no prohíbe que no sea constante
Pues bien, el constructor copia sirve para inicializar un objeto a imagen y semejanza de otro ya existente. Se usan para evitar crear copias recursivas del objeto.
Ejemplo :
struct Test
{ int var;
Test(Test t) //Constructor copia.
{ var = t.var; }
};
En el momento en el que se tuviese que llamar al constructor copia se tendría que hacer antes una copia temporal del objeto original para almacenarla en t. Al crear esa copia se entraría en el constructor copia otra vez y esto originaría otra copia, que provocaría otra llamada al constructor... y así hasta que la pila se desborda.
Al usar referencias se evitan las copias y con ello esta problemática de la llamada recursiva.
Adicionalmente, la referencia se marca como constante para evitar que, por error, el objeto original pueda verse modificado.
using namespace std;
class Test
{
int var;
public:
//Constructor copia.
Test(){var=0;}
//Constructor copia.
Test(Test &t) { var = t.var; };
//Métodos
int mostrar(void){return var;};
void cargar(int z){var=z;};
};
int main(int argc, char *argv[]) {
Test X;
cout<<X.mostrar()<<endl;
X.cargar(3);
cout<<X.mostrar()<<endl;
//Y=X; si sería una asiganción!
Test Y(X);//Manera 1 de invocar al const. copia.
//Test Y=X; //Manera 2 de invocar el const. copia.
cout<<Y.mostrar()<<endl;
Y.cargar(4);//Cambio el valor de var en Y, pero no en X.
cout<<Y.mostrar()<<endl;
cout<<X.mostrar()<<endl;
return 0;
}
3. Métodos Static
l intentar compilar va a titrar un error por que intentamos usar un método NO STATIC para borrar una variable STATIC
Recordemos de manera genérica como se organiza la memoria de un Programa.
Lo que sea declarado con la palabra STATIC, será una zona común para TODOS los objetos que sean de la misma clase.
Es evidente que esto no es importante para un método o función, ya que NO tiene datos.
Pero para el caso de Métodos declarados como STATIC, permiten acceder a los datos
miembro de la clase que sean static.
Esto significa que no tienen puntero this, y además suelen ser usadas con su nombre completo, incluyendo el nombre de la clase y el operador de ámbito (::).
Vemos en el Ejemplo siguiente que si comento la línea
// static int ObjetosDeclarados;//Datios Static
//int ObjetosDeclarados;//Datios Static
Al intentar compilar va a titrar un error por que intentamos usar un método NO STATIC para borrar una variable STATICPor ejemplo:
#include
using namespace std;
class Numero {
public:
Numero(int v = 0);
void Modifica(int v) { Valor = v; }
int LeeValor() const { return Valor; }
int LeeDeclaraciones() const { return ObjetosDeclarados; }
static void Reset() { ObjetosDeclarados = 0; }//Método Static
private:
int Valor;
static int ObjetosDeclarados;//Datios Static
//int ObjetosDeclarados;//Datios Static
};
Numero::Numero(int v) : Valor(v) {
ObjetosDeclarados++;
}
int Numero::ObjetosDeclarados = 0;
int main() {
Numero A(6), B(3), C(9), D(18), E(3);//Varios Objetos.
Numero *X;//Puntero al Objeto.
cout << "INICIAL" << endl;
cout << "Objetos de la clase Numeros: "
<< A.LeeDeclaraciones() << endl;
Numero::Reset();//Método Static modifica Datos Static.
cout << "RESET" << endl;
cout << "Objetos de la clase Numeros: (Metodo Static modifica Datos Static) "
<< A.LeeDeclaraciones() << endl;
X = new Numero(548);
cout << "Cuenta de objetos dinamicos declarados" << endl;
cout << "Objetos de la clase Numeros: "
<< A.LeeDeclaraciones() << endl;
delete X;
X = new Numero(8);
cout << "Cuenta de objetos dinamicos declarados" << endl;
cout << "Objetos de la clase Numeros: "
<< A.LeeDeclaraciones() << endl;
delete X;
cin.get();
return 0;
}
Observa cómo hemos llamado a la función Reset con su nombre completo. Aunque podríamos haber usado "A.Reset()", es más lógico usar el nombre completo, ya que la función puede ser invocada aunque no exista ningún objeto de la clase.
4. Funciones miembro constantes
Esta es una propiedad que nos será muy útil en la depuración de nuestras clases. Además proporciona ciertos mecanismos necesarios para mantener la protección de los datos.
Cuando una función miembro no modifique el valor de ningún dato de la clase, podemos y debemos declararla como constante. Esto no evitará que la función intente modificar los datos del objeto; a fin de cuentas, el código de la función lo escribimos nosotros; pero generará un error durante la compilación si la función intenta modificar alguno de los datos miembro del objeto.
Por ejemplo:
#include
using namespace std;
class Ejemplo2 {
public:
Ejemplo2(int a){A=a;};
void Modifica(int a) { A = a; }
//Método
int Lee() const { return A; }// Ver que método Lee es CONTS!!
//int Lee() const { A++; return A; }//intenta Modificar!!
//int Lee() const { Modifica(A+1); return A; }//intenta Modificar!!
//int Lee() const { Modifica(3); return A; }//intenta Modificar!!
private:
int A;
};
int main() {
Ejemplo2 X(6);
cout << X.Lee() << endl;
X.Modifica(2);
cout << X.Lee() << endl;
cin.get();
return 0;
}
Para experimentar, comprueba lo que pasa si cambias la definición de la función "Lee()" por estas otras, algunas de las comentadas en las líneas 12,13 o 14 :
int Lee() const { A++; return A; } int Lee() const { Modifica(A+1); return A; } int Lee() const { Modifica(3); return A; }
Verás que el compilador no lo permite.
Evidentemente, si somos nosotros los que escribimos el código de la función, sabemos si la función modifica o no los datos, de modo que en rigor no necesitamos saber si es o no constante, pero frecuentemente otros programadores pueden usar clases definidas por nosotros, o nosotros las definidas por otros. En ese caso es frecuente que sólo se disponga de la declaración de la clase, y el modificador "const" nos dice si cierto modifica o no los datos del objeto.
Valores de retorno constantes
Otra técnica muy útil y aconsejable en muchos casos es usar valores de retorno de las funciones constantes, en particular cuando se usen para devolver punteros miembro de la clase.
Por ejemplo, supongamos que tenemos una clase para cadenas de caracteres:
class cadena {
public:
cadena(); // Constructor por defecto
cadena(char *c); // Constructor desde cadena c
cadena(int n); // Constructor para cadena de n caracteres
cadena(const cadena &); // Constructor copia
~cadena(); // Destructor
void Asignar(char *dest);
char *Leer(char *c) {
strcpy(c, cad);
return c;
}
private:
char *cad; // Puntero a char: cadena de caracteres
};
Si te fijas en la función "Leer", verás que devuelve un puntero a la cadena que pasamos como parámetro, después de copiar el valor de cad en esa cadena. Esto es necesario para mantener la protección de cad, si nos limitáramos a devolver ese parámetro, el programa podría modificar la cadena almacenada a pesar de se cad un miembro privado:
char *Leer() { return cad; }
Para evitar eso podemos declarar el valor de retorno de la función "Leer" como constante:
const char *Leer() { return cad; }
De este modo, el programa que lea la cadena mediante esta función no podrá modificar ni el valor del puntero ni su contenido. Por ejemplo:
class cadena { ... }; ... int main() { cadena Cadena1("hola"); cout << Cadena1.Leer() << endl; // Legal Cadena1.Leer() = cadena2; // Ilegal Cadena1.Leer()[1] = 'O'; // Ilegal }
5. Ejemplo de Listas enlazadas con clase
En este capítulo vamos a plantear ejemplos varios ejemplos sencillos de como hacer una lista enlazada simple manejada por una clase.
Vamos a evitar cuestiones que conocemos, como por ejemplo hacer un menú, etc en vista de lograr tener pocas líneas de código, todas explicadas.
Vamos con el primero:
Consigna:
Crear una clase que cargue una lista enlazada simple. La clase tendrá 3 métodos. Cargar, Mostar y Borrar. La estructura NO es parte de la clase.
6. Ejercicio Molinos de Café
Una empresa cuenta con un sistema dispensador de café molido.
Consta
de varios molinos que comparten un depósito (silo) común. Cuando
arranca el proceso el silo está lleno y contiene 200 kg de café en
granos y ningún molino activo.
Durante la producción se puede acoplar
más molinos hasta llegar a un total de 20 cabezales. Los molinos se
identifican con letras sucesivas del alfabeto: a, b, c, etc.
Se requiere un programa en C++ que presente un menú con las siguientes opciones:
1: agregar molino
2: mostrar reporte (muestra un informe de la cantidad en depósito, lo molido por cada cabezal y el total molido)
a, b, c, etc: operar sobre el molino correspondiente
0: salir
Cada molino será el objeto de una clase. La clase tendrá como mínimo las siguientes propiedades:
-ID: a, b, c, etc (se completa automáticamente al momento de crear el objeto)
-disponible contiene el dato del café que queda en el silo
-molido cantidad de café molido por el cabezal
Además tendrá los métodos:
moler() pide el ingreso de la cantidad a moler y ajusta las propiedades
recargar()
pide el ingreso de la cantidad a recargar en el silo y ajusta la
propiedad. (esto se puede hacer desde cualquier molino)
6.1. ejemplo de solución
/*
* Germán Andrés Xander 2021 *
*/
#include <iostream>
#define capacidad 200
#define molinos 20
using namespace std;
class molino{
public:
char ID=0;
static float disponible;
float molido=0;
void moler(float cantidad){
if (disponible >= cantidad){
disponible -= cantidad;
molido+=cantidad;
cout<<endl<<"se molieron "<<cantidad<<" kg."<<endl<<"quedan disponibles "<<disponible<<" kg en el silo"<<endl;
}else{
cout<<endl<<"no hay suficiente café disponible"<<endl;
}
}
void recargar(float cantidad){
if ((disponible + cantidad)<= capacidad){
disponible += cantidad;
cout<<endl<<"se agregaron "<<cantidad<<" kg."<<endl<<"el silo ahora tiene "<<disponible<<" kg de café"<<endl;
}else{
cout<<endl<<"No fue posible cargar. Se excede la capacidad del silo"<<endl;
}
}
molino * proximo;
};
float molino::disponible = capacidad;
void agregar(molino *&lista);
void reporte(molino *lista);
void operar(char id, molino *lista);
void eliminar(molino *&lista);
int main(int argc, char **argv){
char opcion;
molino * planta=NULL;
do{
cout<<endl<<endl<<endl<<"1 agregar molino"<<endl<<"2 reporte"<<endl<<"(a,b,c...) operar molino "<<endl<<"0 salir"<<endl;
cin>>opcion;
switch (opcion){
case '1':{
agregar(planta);
break;
}
case '2': {
reporte(planta);
break;
}
case '0': {
cout<<endl<<"saliendo";
break;
}
default:{
if (opcion < 'a' or opcion >= 'a'+ molinos){
cout<<endl<<"opción no valida";
}else{
operar(opcion,planta);
}
}
}
}while(opcion!='0');
eliminar(planta);
return 0;
}
void agregar(molino *&lista){
int cantidad=1;
molino *lista2=lista;
char id='a';
if (!lista){ //el primero
lista=new molino;
lista->ID=id;
lista->proximo=NULL;
}else{
while(lista2->proximo!=NULL){
lista2=lista2->proximo;
cantidad++;
}
if(cantidad < molinos){
id=lista2->ID;
lista2->proximo=new molino;
lista2->proximo->ID=id+1;
lista2->proximo->proximo=NULL;
}else{
cout<<endl<<"se alcanzo el limite de molinos";
}
}
}
void reporte(molino *lista){
float total=0;
cout<<endl<<endl<<"======== Reporte ==========";
while(lista!=NULL){
cout<<endl<<"Planta id: "<<lista->ID;
cout<<endl<<"Molido: "<<lista->molido<<endl;
total+=lista->molido;
lista=lista->proximo;
}
cout<<endl<<"===========================";
cout<<endl<<"Total molido: "<<total<<" kg";
cout<<endl<<"Disponible: "<<lista->disponible<<" kg";
}
void operar(char id, molino *lista){
char opcion;
float cantidad;
while(lista!=NULL){
if(id==lista->ID){
do{
cout<<endl<<endl<<endl<<"1 Moler"<<endl<<"2 Recargar"<<endl<<"0 Volver"<<endl;
cin>>opcion;
switch (opcion){
case '1':{
cout<<endl<<"ingrese cantidad a moler"<<endl;
cin>>cantidad;
lista->moler(cantidad);
break;
}
case '2': {
cout<<endl<<"ingrese cantidad a recargar"<<endl;
cin>>cantidad;
lista->recargar(cantidad);
break;
}
}
}while(opcion!='0');
break;
}
lista=lista->proximo;
}
cout<<endl<<"no existe el molino solicitado";
}
void eliminar(molino *&lista){
molino *lista2;
while(lista){
lista2=lista;
lista=lista->proximo;
delete lista2;
}
}