Ejercicio 2 | P2 GIR Saltearse al contenido

Ejercicio 2

Ejercicio 2: Genericidad (3.5 puntos)

En este ejercicio vas a aplicar el concepto de genericidad en C++ usando plantillas (templates) para transformar una clase concreta en una clase genérica y reutilizable. Se te proporciona una clase que no utiliza plantillas y tendrás que crear una plantilla en base a esa clase.

Descripción general

Se proporciona una clase IntBox, que representa un contenedor capaz de almacenar un conjunto de enteros (int16_t) en una estructura de tamaño fijo. Tu objetivo será generalizar el código para poder construir contenedores (Box) que puedan almacenar cualquier tipo de dato. El contenedor genérico permitirá configurar el tamaño del mismo como un parámetro de plantilla a la hora de declarar las variables de tipo Box, de manera que, al crear un nuevo objeto de tipo Box, se le indicará el tipo de datos que almacenará y cuántos elementos es capaz de almacenar.


Código base proporcionado

Se te proporciona el siguiente código funcional pero no generalizado, implementado en intbox.h y en intbox.cc. Estos ficheros se encuentran en la carpeta e2 de los archivos de partida.

intbox.h

IntBox.h
#ifndef __INTBOX_H__
#define __INTBOX_H__
#include <cstdint>
namespace C3
{
class IntBox {
public:
IntBox();
void add(int16_t value);
int16_t get(uint32_t index) const;
uint32_t size() const;
private:
int16_t data[100];
uint32_t count;
};
}
#endif /*__INTBOX_H__*/

intbox.cc

IntBox.cc
#include "intbox.h"
#include <stdexcept>
namespace C3
{
IntBox::IntBox() : count(0) {}
void IntBox::add(int16_t value) {
if (count >= 100) throw std::runtime_error("Box is full");
data[count++] = value;
}
int16_t IntBox::get(uint32_t index) const {
if (index >= count) throw std::out_of_range("Invalid index");
return data[index];
}
uint32_t IntBox::size() const {
return count;
}
}
  • Fíjate en el detalle de que, aunque el contenedor de enteros tiene elementos de tipo int16_t, también se trabaja con int32_t, pero este tipo de dato se utiliza para representar una posición dentro del contenedor. Tenlo en cuenta ya que son dos tipos de datos diferentes.

Tarea

Debes crear una clase nueva llamada Box basándote en IntBox y utilizando las plantillas de C++ (template) para permitir almacenar elementos de cualquier tipo, no solo enteros. Esta clase nueva se llamará Box<T, N>, donde:

  • T es el tipo de los elementos que contiene el contenedor.
  • N es la capacidad máxima del contenedor (definida en tiempo de compilación).

Requisitos

  • La clase debe llamarse Box.
  • Se debe separar la interfaz (en el archivo box.h) y la implementación (en box.tcc), como es habitual al trabajar con templates. Ten en cuenta que el fichero de implementación tiene extensión .tcc, no es .cc.
  • Debe ser una clase plantilla con dos parámetros: el tipo T y la capacidad N.
  • Debes implementar los métodos add, get y size, siguiendo la implementación proporcionada en la clase IntBox. La lógica de las funciones deberá ser exactamente la misma que en IntBox, incluyendo los casos en los que se lanza una excepción. Fíjate en la implementación del fichero intbox.cc para implementar tu fichero box.tcc.
  • La clase debe estar definida en el espacio de nombres C3, igual que ocurre con la clase IntBox.

Ejemplo de uso

main_e2.cc
#include <iostream>
#include "box.h"
#include "intbox.h"
using namespace C3;
using namespace std;
int main()
{
//************************************
// Ejemplo de uso de IntBox...
//************************************
std::cout << "**** IntBox ****" << std::endl;
IntBox values;
values.add(10);
values.add(5);
std::cout << "Tamaño: " << values.size() << std::endl;
std::cout << "Elemento 1: " << values.get(1) << std::endl;
std::cout << endl;
//************************************
// Ejemplo de uso de Box genérico...
//************************************
std::cout << "**** BOX ****" << std::endl;
Box<std::string, 10> words;
words.add("hola");
words.add("mundo");
std::cout << "Tamaño: " << words.size() << std::endl;
std::cout << "Elemento 1: " << words.get(1) << std::endl;
try
{
words.get(4); //No existe esta posición, y esta función lanza una excepción con throw.
}
catch(const std::exception& e)
{
std::cout << "No existe la posición accedida en la caja" << std::endl;
}
return 0;
}

La salida de consola de este código debería ser:

**** IntBox ****
Tamaño: 2
Elemento 1: 5
**** BOX ****
Tamaño: 2
Elemento 1: mundo
No existe la posición accedida en la caja
  • Modifica el fichero main_e2.cc tanto como necesites para probar que tu código funciona correctamente.

Entrega

  • Recuerda que puedes crear el archivo comprimido irp2-c3.tgz automáticamente si utilizas el Makefile con la instrucción make tgz. Este archivo contendrá tanto el ejercicio 1 como el ejercicio 2. Tienes más información en el apartado de Instrucciones del examen de prácticas.

  • Un error de compilación/enlace implicará un cero en el ejercicio donde se produzca, por tanto asegúrate de que tu código compila correctamente aunque determinadas funciones no hagan nada o no lo hagan bien.

  • Recuerda que al principio de todos los ficheros fuente (`.h’ y `.cc’) entregados y escritos por ti se debe incluir un comentario con tu NIF (o equivalente) y tu nombre, como en el siguiente ejemplo. Ponlo exactamente igual, cambiando los datos personales por los tuyos.

    // NIF: 12345678-Z
    // NOMBRE: GARCIA PEREZ, LAURA
  • Lugar y fecha de entrega : La entregas se realiza siempre en (y sólo en) https://pracdlsi.dlsi.ua.es en las fechas y condiciones allí publicadas. Puedes entregar los ejercicios tantas veces como quieras, sólo se corregirá la última entrega (las anteriores no se borran). El usuario y contraseña para entregar prácticas es el mismo que se utiliza en UACloud.