Logo Studenta

UC3M _ Grado en Ingeniería Electrónica _ Informatica industrial _C____ I_Electronica_uc3m_ _ informatic

Esta es una vista previa del archivo. Inicie sesión para ver el archivo original

informatica industrial/practicas/P2 - Clases I.pdf
	
 
 
 
 
 
 
 
Práctica	de	Informática	Industrial	I	
Grado	en	Ingeniería	en	Electrónica	Industrial	y	Automática	
2015‐2016
Práctica	2	
Clases	I.	Definición,	Constructores,	Destructores,	… 
 
 
 
Profesores: 
            Mohamed Abderrahim 
           Álvaro Castro González 
           Ioannis Douratsos  
           José Carlos Castillo 
           Javier Fernandez de Gorostiza 
          Juan Carlos González Victores 
 
Informática Industrial 2015/2016 2/11 Práctica 2 
 
Práctica 2 - Clases 
1. Clases 
1.1. Definición 
Lo primero que se va a ver es como se estructura un fichero main.cpp en C++. 
 
//////////////////////////////////////////////////// 
// main.cpp 
//////////////////////////////////////////////////// 
 
#include <iostream> 
#include “point.h” 
 
using namespace std; 
using namespace space; 
 
int main(int argc, char **argv) { 
  Point P; 
  cout << P.getX() << endl; 
  cout << P.getY() << endl; 
 
  P.set(10, 10); 
  cout << P.getX() << endl; 
  cout << P.getY() << endl; 
 
  P.display(); 
} 
 
En este programa, lo primero que se hace es incluir la biblioteca estándar de C++ y el fichero de 
cabecera point.h, que contendrá la declaración de la clase que se va a crear posteriormente. 
Nótese que la biblioteca estándar no se incluye de igual manera que en C, por ejemplo, en el que 
sería iostream.h. En C++, la mayoría de los ficheros de inclusión estándar, acaban sin .h y a 
veces comienzan con la letra “c”. 
Algunos ejemplos de ficheros de C que pasan a C++ son: 
 
#include <stdlib.h>  →  #include <cstdlib> 
#include <assert.h>  → #include <cassert> 
 
Después, se pueden encontrar las directivas: 
 
using namespace std; 
using namespace space; 
 
Informática Industrial 2012/2013 3/11 Práctica 2 
Estas indican al compilador que se van a usar los espacios de nombres std (estándar) y space (que 
se crea por el usuario más adelante). En C++, las clases se pueden encapsular en espacios de 
nombres. De esta forma se organizan mejor para proyectos grandes. El espacio de nombres std 
define el espacio de nombres estándar de C++. Si no se indica explícitamente que se va a usar, el 
compilador dará un error al tratar de usar por ejemplo cout, ya que esta es una clase de este espacio 
de nombres. En caso de no especificar el espacio de nombre y para que no de error al utilizar alguna 
de estas funciones, se puede llamarlo de forma explícita utilizando std::cout. 
En la función main, observar la siguiente declaración: 
 
Point P; 
 
Esto está indicando al compilador que debe crear una variable de tipo Point. Es decir, que se va a 
crear una variable de la clase Point, o también se dice que se ha creado un objeto de la clase 
Point. 
Como ya se ha visto en teoría, se llama a los métodos de una clase usando el operador “.” (punto). 
Por eso, la expresión P.getX() es una llamada a la función miembro getX() del objeto P. 
Si se considera el código siguiente: 
 
Point P, P2; 
cout << P.getX() << endl; 
cout << P2.getX() << endl; 
 
Se estarían creando dos objetos distintos, ambos de la clase Point. Y P.getX() sería una llamada 
a la función miembro del objeto, que sería distinto a llamar a p2.getX(). La diferencia, como se 
verá más adelante, es que P.getX() usará los valores del objeto P, y P2.getX() usara los valores 
de P2. 
En este momento ya se puede ver cómo se va a definir una clase. Una clase se define en dos 
ficheros, un fichero .h y un fichero .cpp. El fichero .h contiene la definición o declaración de la 
clase, mientras que el .cpp contiene la implementación de la clase. 
Las clases se pueden definir dentro de un espacio de nombres “namespace”. Los espacios de 
nombres comienzan por letra minúscula (por convenio). El nombre de las clases comienza con 
mayúscula (por convenio). La clase Point representará un punto en el espacio. Esta clase 
permitirá manejar un punto mediante las funciones miembro o métodos de la clase. 
Las clases se definen usando la palabra clave class. Seguidamente se define la parte pública, es 
decir, aquella que podrá ser usada por otras clases o funciones. Más adelante se define la privada, 
donde se colocan las variables o funciones que solo podrán accederse desde funciones miembro de 
la misma clase. 
A continuación se muestra el fichero point.h. 
Informática Industrial 2012/2013 4/11 Práctica 2 
 
//////////////////////////////////////////////////// 
// point.h 
//////////////////////////////////////////////////// 
 
#ifndef _POINT_H_ 
#define _POINT_H_ 
 
#include <iostream> 
 
using namespace std; 
 
namespace space { 
  /**\brief This class represents a point 
  */ 
  class Point { 
    public: 
      int getX(); 
      int getY(); 
      void set(int x, int y); 
      void display(); 
    private: 
      int _x, _y; 
  }; 
} 
 
#endif 
 
Dentro de la clase se han definido dos variables privadas y cuatro métodos públicos. El primer y 
segundo método sirven para obtener los valores de las coordenadas del punto, el segundo método 
sirve para especificar los valores del punto, y el tercer método sirve para ver los valores de las 
coordenadas del punto. Finalmente, en la parte privada, se han declarado dos enteros que 
representan los valores del punto de la clase. Las variables privadas se declaran comenzando por 
subrayado “_” (por convenio). 
Para ocultar los detalles de implementación de una clase y así permitir cambiar su implementación 
sin tener que cambiar el resto del código que la utiliza, C++ introduce los especificadores de 
acceso. Estos permiten definir qué miembros de una clase son accesibles desde fuera de ésta y 
cuáles no. Hay tres especificadores de acceso: public, private y protected. El primero, public, 
significa que el miembro es accesible desde fuera de la definición de la clase, mientras que los 
miembros private y protected sólo se pueden acceder desde dentro de las funciones de la clase o 
las clases habilitadas para ello. Por defecto, todos los miembros de una clase son privados. 
Si se intenta acceder a un atributo o método privado, el compilador dará un error y no se podrá crear 
el ejecutable. En el siguiente código se puede probar como fallaría la compilación del main.cpp. 
Informática Industrial 2012/2013 5/11 Práctica 2 
 
int main() {  
  Point P; 
  P._x = 10; // imposible! ERROR! 
  P.display(); 
} 
 
Otro aspecto muy importante de la programación es la documentación. Se deben documentar todos 
los ficheros fuente que se realicen. Los comentarios tendrán formato Doxygen como el que se 
muestra a continuación: 
 
/** 
*/ 
 
Para este formato de documentación existen herramientas que nos crearán una documentación 
HTML del código y que se podrá consultar en cualquier navegador. 
Ahora, se va a crear el .cpp. 
 
//////////////////////////////////////////////////// 
// point.cpp 
//////////////////////////////////////////////////// 
 
#include "point.h"   
 
namespace space { 
   //////////////////////////////////// 
  // 
  //////////////////////////////////// 
  int Point::getX() { 
    return _x; 
  } 
 
  //////////////////////////////////// 
  // 
  //////////////////////////////////// 
  int Point::getY() { 
    return _y; 
  } 
 
  //////////////////////////////////// 
  // 
  //////////////////////////////////// 
  void Point::set(int x, int y) { 
    _x = x; 
    _y = y; 
  } 
 
  //////////////////////////////////// 
  // 
Informática Industrial 2012/2013 6/11 Práctica 2 
  //////////////////////////////////// 
  void Point::display() {  
    cout << _x << “, “ << _y << endl; 
  } 
} 
 
Finalmente, compilar haciendo uso de QtCreator y ejecutar el programa. 
1.2. Constructores y destructores 
1.2.1. Constructores 
Probablemente, ya se habrán dado cuenta que cuando se instancia un objeto de una clase, los 
valores de los atributos de la clase tienen valor inicial “basura”. Sin embargo, es posible alterar 
este comportamiento de la clase añadiendo constructores. El constructor es una función que se 
invoca al
crear un objeto de la clase, pero para ello ha de estar definida. 
Constructor vacío 
Crear primero el constructor vacio. Añadir el siguiente código a la definición de la clase justo 
debajo de la palabra clave “public”. 
 
 
/** Empty constructor 
*/ 
Point(); 
 
Esto es un constructor, que es una función miembro que no devuelve nada y que se llama igual que 
la clase. Fíjese muy bien que no solo no devuelve nada, sino que tan siquiera dice void. Al ser una 
función miembro puede tener parámetros, pero en este caso se encuentra vacío de parámetros. Los 
constructores siempre son las primeras funciones de la clase y deben ser públicos. Ahora ver la 
implementación en el .cpp. 
 
 
/////////////////////////// 
// 
///////////////////////// 
Point::Point() { 
  _x = 0; 
  _y = 0; 
} 
 
Lo que se hace es inicializar las variables de la clase a valor 0, por ejemplo, para que no sea 
“basura” al crearse el objeto. Finalmente, volver a compilar y ejecutar. Como se observa, la salida 
ahora es 0. 
Sobrecarga de constructores 
En C++ es posible crear varias funciones miembro con el mismo nombre aunque con diferentes 
argumentos, a esto se le llama sobrecarga. Será el compilador el que se encargue de decidir a qué 
Informática Industrial 2012/2013 7/11 Práctica 2 
función se debe llamar dependiendo de los argumentos que se usen. 
Se va a probar la sobrecarga añadiendo dos constructores típicos que son: el constructor 
parametrizado y el constructor de copia. El primero servirá para asignar un valor a las variables 
en la creación de la clase y el segundo servirá para crear un objeto que sea copia de otro. Añadir el 
siguiente código al .h. 
 
 
/** Parametrized constructor 
*/ 
Point(int x, int y); 
 
/** Copy constructor 
*/ 
Point(const Point & P); 
 
Y ahora habrá que completar el .cpp. 
 
 
/////////////////////////// 
// 
///////////////////////// 
Point::Point(int x, int y) { 
  _x = x; 
  _y = y; 
} 
  
/////////////////////////// 
// 
///////////////////////// 
Point::Point(const Point & P) { 
  _x = P._x; 
  _y = P._y; 
} 
 
Obsérvese que el primer constructor recibe como argumento valores enteros y los asigna a las 
variables. El segundo requiere un poco mas de explicación. Se denomina constructor de copia y lo 
que hace es que hace que el objeto creado sea una copia del que se pasa. El argumento (único) es 
una referencia a un objeto de la misma clase. 
 
const Point & P 
 
La palabra clave const sirve para indicar que el elemento pasado no debe ser modificado en el 
interior de la función. Después se observa el símbolo &. En C hay dos formas básicas de pasar 
argumentos, por valor y por referencia. En el primer caso, se pasaba un elemento y dentro de la 
función se hacia una copia con la que se trabajaba. Por referencia (puntero), se pasaba la 
dirección de memoria y se podía modificar el valor directamente. 
Cuando se quiere pasar como parámetro a una clase en C++, se tiene la misma idea, paso por 
Informática Industrial 2012/2013 8/11 Práctica 2 
valor o por referencia. Sin embargo, el paso por valor no es recomendable cuando se pasa a una 
clase. Esto es porque las clases pueden contener una gran cantidad de variables y el realizar una 
copia podría llegar a ser muy costoso e ineficiente. Por tanto, es preferible hacer el paso de un 
objeto siempre por referencia. Para ello, en C++ se define el operador &. Cuando se pasa &, se 
está indicando que se puede modificar el valor de la variable dentro de la función. Las referencias 
se verán con detalle en la siguiente práctica. Ahora se puede ver un ejemplo simple. 
 
 
main() { 
  int v = 10; 
  modify(v); 
  cout << v << endl; 
} 
  
void modify(int & v) { 
  v = 0; 
} 
 
En el caso del constructor de copia, se está pasando por referencia el objeto (para evitar una copia 
de todos sus datos), pero a la vez se le está diciendo que se haga constante. Es decir, que no sea 
posible modificar sus valores en el interior. Por tanto, el siguiente código sería incorrecto: 
 
 
/////////////////////////// 
// 
///////////////////////// 
Point::Point(const Point & P) { 
  P._x = 100; 
  P._y = 101; 
} 
 
Ya que se está modificando las variables internas del objeto pasado P, que se supone que es 
constante dentro de la función. 
 
1.2.2. Destructores 
El destructor es la función a la que se llama cuando se debe destruir el objeto. Es decir, la función 
a la que se llama cuando ya no se va a usar el objeto nunca más. Si se define en el .h. 
 
/** Destructor 
*/ 
~Point(); 
 
Ahora se tiene algo nuevo ~Point(). Esto será el destructor de la clase. El objeto tendrá que 
liberar la memoria en caso de que se hubiese creado. Lo bueno de los destructores es que es una 
función a la que llama el compilador automáticamente cuando detecta que el objeto no se va a 
usar más. No se tiene que llamar al destructor, el compilador lo hace por el usuario. En el caso del 
ejemplo de la clase Point, el destructor no hará nada de momento pero cuando se vea la reserva 
Informática Industrial 2012/2013 9/11 Práctica 2 
de memoria dinámica en la siguiente práctica se verá que será muy útil. 
El código que iría en el .cpp sería: 
 
/////////////////////////// 
// 
///////////////////////// 
Point::~Point() { 
} 
 
 
1.2.3. Operadores 
Otra de las ventajas de las clases es que se pueden definir operadores sobre las clases (=, +, -, *, 
/). Se va a definir el operador de asignación. Añadir en la parte publica de la clase Point la 
siguiente definición: 
 
 
/** Assign operator 
*/ 
Point & operator=(const Point & P); 
 
Y en el .cpp: 
 
 
/////////////////////////// 
// 
///////////////////////// 
Point & Point::operator=(const Point & P) { 
  _x = P._x; 
  _y = P._y; 
 
  return *this; 
} 
 
Los operadores son funciones miembro que permiten definir operaciones habituales. Todos los 
operadores devuelven una copia del objeto actual con el objetivo de poder realizar un 
encadenamiento. 
El valor de retorno es Point &, es decir, una referencia a un objeto de la clase. Si se observa la 
implementación, una vez se realiza la copia, se retorna *this. La palabra reservada this, es 
puntero al objeto actual. El puntero this, usado dentro de una función de la clase Point, es un 
puntero al objeto, por tanto en este caso es un puntero de tipo Point *. Si this es un Point *, 
entonces *this es el propio objeto, es decir Point. Entonces, lo que se está devolviendo es el 
propio objeto. Ver un ejemplo: 
 
Informática Industrial 2012/2013 10/11 Práctica 2 
 
int main(int argc, char **argv) { 
  Point P(10, 10); // parametrized constructor 
  Point P2; 
  cout << P2.getX() << endl; 
  cout << P2.getY() << endl; 
  P2 = P; 
  P2.display(); 
} 
 
En este ejemplo, P es asignado a P2. Por tanto, P2 será una copia de P. Se puede ver ahora 
entonces: 
 
 
int main(int argc, char **argv) { 
  Point P(10); 
  Point P2, P3; 
  P2.display(); 
  P3 = P2 = P; 
  P3.display(); 
} 
 
En este ejemplo, P es asignado a P2, que a su vez es asignado a P3. Al escribir P3 = P2 = P, el 
compilador primero realizará P2 = P. El resultado de esta operación es P2, que será asignado a 
P3. Es decir, el compilador descompondrá las operaciones en: 
 
 
P2 = P; 
P3 = P2; 
 
Esto es posible gracias a que el resultado de la asignación es un Point &. 
 
Informática Industrial 2012/2013 11/11 Práctica 2 
Ejercicios 
 Implementar las clases necesarias para realizar una base de datos de personas. Para ello, se 
debe definir: 
o Una clase Person en un fichero Person.h, y la implementación de sus funciones 
miembro en un fichero Person.cpp. 
 Deberá contener dos atributos privados, _name, de tipo string y _age de 
tipo entero. 
 Deberá contener las siguiente funciones miembro públicas: 
 Constructor vacío, parametrizado y de copia. Realizarán las 
inicializaciones pertinentes. 
 Destructor de la clase. 
 Métodos getName y  setName: obtener y poner el nombre de la 
persona. 
 Métodos getAge y setAge: obtener y poner la edad de la persona. 
 Operador de asignación.
 Realizar un fichero main.cpp en el que la función main deberá realizar lo siguiente: 
o Instanciar un objeto de tipo Person mediante su constructor parametrizado y que se 
muestren por pantalla los datos. 
o Instanciar otro objeto de tipo Person mediante su constructor de copia, teniendo 
como parámetro el objeto anterior y que se muestren los datos de ambos objetos por 
pantalla. 
o Instanciar un último objeto de tipo Person mediante su constructor vacio y llamar a 
sus funciones setAge y setName. Mostrar los datos por pantalla. 
o Instanciar dos objetos más de tipo Person y hacer que valgan lo mismo que el objeto 
anterior utilizando el operador de asignación. 
o Por último, mostrar todos los nombres de las personas que contengan una ‘s’. 
Mostrar todos los nombres de las personas que tengan una edad superior a 18 años. 
 
Notas 
1. Al menos debe haber un resultado. 
2. Se espera que los alumnos completen el trabajo por su cuenta si no logran terminarlo 
durante práctica. 
 
informatica industrial/practicas/P3 - Clases II Memoria dinámica y Referencias.pdf
	
 
 
 
 
 
 
 
Práctica	de	Informática	Industrial	I	
Grado	en	Ingeniería	en	Electrónica	Industrial	y	Automática	
2015‐2016
Práctica	3:	
Clases	II.	Métodos,	Reserva	dinámica	y	Referencias 
 
 
 
 
 
Profesores: 
            Mohamed Abderrahim 
           Álvaro Castro González 
           Ioannis Douratsos  
           José Carlos Castillo 
           Javier Fernandez de Gorostiza 
          Juan Carlos González Victores 
 
Informática Industrial 2015/2016 2/9 Práctica 3 
Práctica 3 – Clases II. Métodos, Reserva dinámica y 
Referencias. 
1. Métodos 
1.1.1. Métodos constantes 
En C++, se puede usar el modificador const para definir una función constante. Mirad en el 
siguiente ejemplo la función getVal(). 
 
class MyC { 
  public: 
    MyC() {_val = 10;} 
    ~MyC() {} 
    void setVal(int v) {_val = v;} 
    int getVal() const {return _val;} 
    int getValNoConst() {return _val;} 
  private: 
    int _val; 
}; 
 
Al declarar una función como constante, le estamos indicando al compilador que la función no 
modificará en su interior el contenido del objeto. Es decir, es una función que accede a los valores, 
pero solo para ver su valor, posiblemente calcular algo usándolos y a lo mejor retornar algo. Pero no 
modificar el estado del objeto, es decir, ninguna de sus variables internas. 
¿Para qué sirve esto? Mirad del siguiente ejemplo. 
   
class MyCC { 
  public: 
    MyCC() {} 
    ~MyCC() {} 
    void readFromMyC(const MyC & M) {_val = M.getVal();} 
  private: 
    float _val; 
}; 
 
La clase MyCC, en la función miembro readFromMyC, se hace que _val valga lo mismo que vale 
getVal(). Darse cuenta que en la declaración se pone const MyC & M, es decir, que M es una 
variable constante. Lo que quiere decir que no se debe poder modificar M dentro de la función. 
Al ser M de tipo constante, el compilador comprobará que no se hacen llamadas que descarten ese 
cualificador (el cualificador constante). Es decir, solo permitirá llamadas a funciones que sean de 
tipo constante. Por tanto, si la variable getVal() de MyC no se hubiese definido como constante, 
no se hubiese podido usar en readFromMyC. O dicho de otro modo, sólo se podrá llamar a 
funciones constantes de objetos que se comportan como constantes. Con lo que el siguiente código 
daría error de compilación: 
Informática Industrial 2015/2016 3/9 Práctica 3 
 
class MyCC { 
  public: 
    MyCC() {} 
    ~MyCC() {} 
    void readFromMyC(const MyC & M) {_val = M.getValNoConst();} 
  private: 
    float _val; 
}; 
 
Pero esto tiene otra limitación. Se ha comentado que al definir una función como constante, no se 
puede modificar el valor del objeto. Por tanto, dentro de una función constante, sólo se podrán hacer 
llamadas a funciones constantes. 
Por ejemplo, el siguiente código daría error de compilación porque foo() se declara como una 
función constante pero dentro se hace una llamada a una función no constante. Aunque en realidad 
la función getValueNoConst() no modifica el objeto _myc, el compilador no lo sabe a priori. El 
compilador “se cura en salud” y dice, “como getValueNoConst() no es contante, podría ocurrir 
que se modificase el objeto. Así que no lo voy a permitir”. 
 
class MyCCC { 
  public: 
    MyCCC() {} 
    ~MyCCC() {} 
    int foo() const {return  _myc.getValNoConst()*10;} 
  private: 
    MyC _myc; 
}; 
 
¿Cuál sería la solución al problema? Pues llamar a una función constante. El siguiente código si 
sería correcto: 
 
class MyCCC { 
  public: 
    MyCCC() {} 
    ~MyCCC() {} 
    int foo() const {return  _myc.getVal()*10;} 
  private: 
    MyC _myc; 
}; 
 
2. Memoria dinámica y Referencias 
2.1. Reserva y liberación de memoria 
Para la reserva de memoria dinámica se usa la directiva new. Y para la liberación de la misma se 
utiliza delete. Incluir lo siguiente en el .h de la clase Point como variable pública: 
Informática Industrial 2015/2016 4/9 Práctica 3 
 
int size; 
int *v; 
 
Ahora, añadir al constructor vacío lo siguiente: 
 
size = 2; 
v = new int[size]; 
for (int i = 0; i < size; i++) { 
  v[i] = 0; 
} 
 
Como se puede observar, se crea un vector de tipo entero de 10 elementos. Y en el constructor vacío 
de la clase se reserva memoria y se inicializan sus valores. 
La sintaxis general para la reserva de memoria en C++ es: 
 
 
tipo_dato *var = new tipo_dato[numero_elementos]; 
 
Lo bueno de new es que el calcula el tamaño de la memoria por el usuario. Probar el siguiente 
código de ejemplo: 
 
#include <iostream> 
 
using namespace std; 
 
int main() { 
  int *v = new int[10]; // vector entero de 10 elementos 
  v[0] = v[1] = 1; 
  cout << v[0] << ", " << v[1] << endl; 
  delete[] v; 
} 
 
Además, este mismo ejemplo se podría aplicar dentro de una clase. Si se vuelve a tomar la clase 
Point y se añade una variable pública int *v; en el constructor de la clase se podrá inicializar 
reservando memoria para dicho vector. 
Informática Industrial 2015/2016 5/9 Práctica 3 
 
/////////////////////////// 
.h 
/////////////////////////// 
 
class Point { 
  public: 
    int *v; 
            int size; 
} 
 
/////////////////////////// 
.cpp 
/////////////////////////// 
 
Point::Point() { 
    size = 10; 
    v = new int[size]; 
    for (int i = 0; i < size; i++) { 
       v[i] = 0; 
    } 
} 
 
Creación dinámica de objetos 
Además de poderse reservar memoria para los tipos básicos, también se puede reservar memoria 
dinámica para los objetos. En este caso sería de la siguiente forma: 
 
main() { 
  Point *P = new Point; 
} 
 
Con esto, se está creando de forma dinámica un objeto de tipo Point. El operador new se encargará 
de llamar al constructor, en este caso al constructor vacío. Aunque también se podría haber escrito 
lo siguiente para llamar a cualquier otro constructor, en este caso al parametrizado. 
 
main() { 
  Point *P1 = new Point(10, 10); 
  P1‐>display(); 
} 
 
Ahora bien, cuando se crea un objeto de forma dinámica hay cambios a la hora de llamar a sus 
funciones miembro. En lugar de usar el operador punto (.), como lo que se tiene es un puntero a un 
objeto (Point *), se usará el operador flecha (‐>). Esta es una de las novedades de C++ y que ya 
se verá como dará una gran potencia de reusabilidad. 
Destrucción de objetos dinámicos 
Informática Industrial 2015/2016 6/9 Práctica 3 
Cuando se acaba de usar el objeto dinámico, no se debe de olvidar de destruirlo. Para ello, se usará 
la sentencia delete, que se encargará de llamar automáticamente al destructor, en caso de estar 
definido. Es importante indicar que si el destructor no está definido no se le podrá llamar. Si ahora 
se pone en el .cpp, siguiendo con el ejemplo anterior: 
 
Point::~Point() { 
  delete[] v; 
} 
 
Se liberará la memoria reservada en el constructor dejándola libre para otros usos. Hacer esto es 
muy importante para no sobrecargar el sistema. 
Ver el siguiente ejemplo completo. 
 
#include <iostream>
#include “point.h” 
 
using namespace std; 
using namespace space; 
 
int main() { 
    // memoria dinamica objetos 
    Point *P = new Point; 
    Point *P1 = new Point(10, 10); 
    P1‐>display(); 
    delete P; 
    delete P1; 
 
    Point *P2 = new Point; 
    for (int i = 0; i < P2‐>size; i++) { 
        cout << "v[" << i << "] = " << P2‐>v[i] << endl; 
    } 
} 
 
En el ejemplo, se crean varios objetos de la clase Point usando new. Después, se muestran sus 
valores y después se destruyen los objetos. Tener en cuenta que para liberar la memoria reservada 
para el objeto no hay que poner los corchetes ([]) como en el vector del ejemplo anterior. 
Posteriormente se crea otro objeto de forma dinámica y se accede a los elementos del vector 
dinámico creado en el interior de la clase. 
Para avanzados 
Si se quiere reservar memoria para una matriz debe tenerse en cuenta ciertos aspectos a la hora de la 
reserva y la liberación de la memoria. Para crear una matriz dinámica de NxM elementos sería: 
Informática Industrial 2015/2016 7/9 Práctica 3 
 
double **matrix = new double*[n]; 
for (int i = 0; i < n; i++) { 
  matrix[i] = new double[m]; 
} 
 
Y para liberar su memoria se haría al revés: 
 
for (int i = 0; i < n; i++) { 
  delete[] matrix[i]; 
} 
delete[] matrix; 
 
2.2. Referencias de objetos 
Para ver como se usan las referencias de objetos el ejemplo típico es mediante el paso de objetos 
dinámicos a funciones. 
 
Una vez se tiene creado el objeto de forma dinámica, ¿cómo se pasa a otra función?. A continuación 
se puede ver un ejemplo de uso. 
 
void modify(Point *P, int v) { 
  P‐>setV(v); // implementar el metodo setV 
} 
  
main() { 
  Point *P = new Point(10, 10); 
  modify(P, 11); 
  cout << P‐>getV() << endl; // implementar el metodo getV 
  delete F; 
} 
 
En el ejemplo, la función recibe un puntero a un objeto de la clase y lo modifica en el interior. Otra 
forma alternativa de escribir la función hubiese sido. 
 
void modify(Point *P, int v) { 
  (*P).setV(v); 
} 
 
Mediante (*P) se accede al contenido del objeto y no a la referencia, con lo que se puede usar el 
operador punto (.) en lugar del operador flecha (‐>). 
Pero se puede ir un poco más allá, se podría tener la siguiente función: 
Informática Industrial 2015/2016 8/9 Práctica 3 
 
void modify(Point & P, int v) { 
  P.setV(v); 
} 
 
 
En este caso se está usando la notación de paso por referencia de C++. Como se ve, es posible 
intercambiar entre las notaciones de C y C++. Para poder llamar a la función, se tendría que haber 
escrito: 
 
 
main() { 
  Point *P = new Point(10, 10); 
  modify(*P, 11); 
  cout << P‐>getV() << endl; 
} 
 
 
Con el que se obtendría el mismo resultado. 
 
Informática Industrial 2015/2016 9/9 Práctica 3 
Ejercicios 
 Utilizando la librería estándar que se ha visto en las prácticas anteriores, escribir un 
programa en C++ que lea un array de n enteros por teclado y muestre la suma de todos ellos. 
El tamaño del array (n) debe ser dinámico y se pedirá al usuario por el teclado al principio 
del programa. 
 Completar la implementación de las clases necesarias para realizar la base de datos de 
personas. Para ello, se debe definir: 
o Una clase PersonList en un fichero PersonList.h, y su implementación en un 
fichero PersonList.cpp. 
 Deberá contener los siguientes atributos privados: 
 Vector de tipo Person: _v. 
 Número de personas: _n. 
 Deberá contener los siguientes métodos públicos: 
 Constructor vacío, parametrizado y de copia. Realizarán las 
inicializaciones pertinentes y las reservas de memoria. 
 Destructor de la clase. Liberará la memoria reservada. 
 Método readData: lee el número de personas a introducir en la base 
de datos y seguidamente los datos de cada una obteniéndolos por 
teclado. 
 Método display: muestra la lista de personas incluidas en la base de 
datos. 
 Operador []: que devuelva el elemento N de tipo Person solicitado. 
 Realizar un fichero main.cpp en el que la función main deberá realizar lo siguiente: 
o Instanciar un objeto de tipo PersonList y llamar a su método readData, pedirá 
al usuario que introduzca por teclado el número de personas a introducir, se reservará 
la memoria de manera dinámica para esas personas y se pedirá por teclado los datos 
de cada una de ellas, seguidamente se llamará al método display, el cual mostrará 
por pantalla el contenido de la base de datos con todas las personas introducidas. 
 
informatica industrial/practicas/P4 - Herencia.pdf
	
 
 
 
 
 
 
 
Práctica	de	Informática	Industrial	I	
Grado	en	Ingeniería	en	Electrónica	Industrial	y	Automática	
2014‐2015
Práctica	4	
Herencia 
 
 
 
 
Profesores: 
           Fares Abu‐Dakka 
           Mohamed Abderrahim 
           Álvaro Castro González 
           Avinash  Ranganath 
           Carlos Alonso 
            Ioannis Douratsos 
 
Informática Industrial 2015/2016 2/7 Práctica 4 
Práctica 4 – Herencia. 
La herencia es una funcionalidad de los lenguajes objetos que permite reutilizar el código de clases 
existentes y extenderlo. 
1. Herencia para extender 
En C++ se puede declarar una clase (llamada clase hija) que derive de otra clase (clase padre). Esto 
implica que la clase hija recuperará todos los miembros de la clase padre y puede ampliarse con 
nuevas funciones miembro. 
El siguiente ejemplo muestra cómo se puede definir una clase punto con color (el color se 
representará con un entero) derivada de la clase Point para recuperar la gestión de las coordenadas 
que ya se ha implementado. 
Poniendo el siguiente código en el .h de la clase Point: 
 
class Point { 
  public: 
    Point(int x, int y);   
 
    void set(int x, int y); 
    int getX() const {return _x;} 
    int getY() const {return _y;} 
 
    void display () const; 
 
  private: 
    int _x, _y; 
} 
 
Y el siguiente en el .h de la nueva clase ColorPoint: 
 
class ColorPoint : public Point { 
  public: 
    ColorPoint(int x, int y, int c) : Point(x, y) {_color = c;} 
    int getColor() const {return _color;} 
 
  private: 
    int _color; 
} 
 
Para el siguiente código de prueba: 
Informática Industrial 2015/2016 3/7 Práctica 4 
 
int main() { 
  ColorPoint CP(10, 20, 255); 
 
  CP.getX();    // come from Point class 
  CP.display();  // come from Point class, display x and y 
  CP.getColor();  // come from PointColor class 
} 
 
Gracias a la herencia, la clase ColorPoint sólo tiene que definir su miembro adicional 
(getColor), y recuperar de la clase Point los miembros relacionados con las coordenadas. Notad 
como el constructor de PointColor llama al constructor de Point que tomará dos parámetros. 
2. Redefinición de una función miembro 
Esta solución todavía no es completamente satisfactoria ya que la función display, heredada de 
Point no muestra el color del punto. Por ello se puede redefinir las funciones miembros cuyo 
comportamiento queremos cambiar en la clase hija. 
Así, la clase Point quedará: 
 
class Point { 
  public: 
    Point(int x, int y);   
    // set, getX, getY 
    void display() const {cout << _x << _y;} 
 
  private: 
    int _x, _y; 
}; 
 
Y la clase ColorPoint: 
 
class ColorPoint : public Point { 
  public: 
    ColorPoint(int x, int y, int c) : Point(x, y) {_color = c;} 
    int getColor() const {return _color;} 
    void display() const {cout << _x << _y << _color;} 
 
  private: 
    int _color; 
}; 
 
De este modo, se puede cambiar el comportamiento de una clase hija con la redefinición de sus 
propios métodos. 
Con lo que el main quedaría: 
Informática Industrial 2015/2016 4/7 Práctica 4 
 
int main() { 
  ColorPoint CP(10, 20, 255); 
  CP.display();  // come from PointColor class, display x, y and color 
 
  Point P(10, 20); 
  P.display();  // come from Point class, display x and y 
} 
 
Nota: En este momento la clase ColorPoint no compilaría. Encontrar el error y proponer una 
solución. 
 
Informática Industrial 2015/2016 5/7 Práctica 4 
Ejercicios 
 Realizar un simulador de ordenador: 
o Para
ilustrar los conceptos de la programación orientada a objetos en C++, se va a 
realizar un pequeño proyecto a lo largo de las prácticas. Este se basará en desarrollar 
un simulador de ordenador. El programa deberá simular teclados, procesadores, 
programas, pantallas, etc. Para que el programa quede sencillo, nuestro ordenador 
solo será capaz de manejar cadenas de caracteres. De momento se propone 
implementar el código que corresponde al diagrama UML del anexo. 
o En concreto, el programa deberá poder leer caracteres desde el teclado, transmitirlos 
al procesador para que los transforme y enviarlos a una pantalla que muestre la 
cadena procesada. El diseño deberá estar pensado para que sea modular, es decir, que 
sea relativamente sencillo añadir o modificar cualquier elemento de las clases. 
o Para cada clase se debe crear un fichero de cabecera nombre_clase.h y un fichero 
fuente nombre_clase.cpp. 
o La descripción de los métodos a implementar se puede encontrar en la tabla del 
anexo. 
 
 
Informática Industrial 2015/2016 6/7 Práctica 4 
Anexo 
Clase Métodos Descripción 
Device 
Device::Device(const string & name)  Inicializa un componente con el nombre especificado 
const string & Device::getName() const  Devuelve el nombre del componente. 
Display 
Display::Display(const string & name)  Inicializa una pantalla con el nombre especificado. 
void Display::process(const string & data)  Muestra la cadena por pantalla utilizando cout. 
Processor 
Processor::Processor(const string & name)  Inicializa un procesador con el nombre especificado. 
void Processor::connectTo(Display & display)  Conecta el procesador con un Display. 
void Processor::process(const string & data) 
Invierte la cadena de caracteres data y añade el prefijo “PROCESSED:
”. Manda el resultado al Display al cual está conectado. Por ejemplo,
si data vale “hola”, la cadena enviada al Display debe ser 
“PROCESSED: aloh”. 
Keyboard 
Keyboard::Keyboard(const string & name)  Inicializa un teclado con el nombre especificado. 
void Keyboard::connectTo(Processor & cpu)  Conecta el teclado con un procesador. 
void Keyboard::process() 
Implementación por defecto de un teclado, lee una cadena de caractere
desde el teclado real utilizando el operador de flujo cin. Después 
manda esta cadena al procesador llamando al método process() del 
procesador al cual está conectado. 
CharKeyboard 
CharKeyboard::CharKeyboard(const string & name)  Inicializa un teclado de caracter con el nombre especificado. 
void CharKeyboard::process()  Igual que Keyboard::process() pero solo lee un carácter (para ello
se puede utilizar la función estándar cin.get()). 
LineKeyboard 
LineKeyboard::LineKeyboard(const string & name)  Inicializa un teclado de línea con el nombre especificado. 
void LineKeyboard::process() 
Igual que Keyboard::process() pero lee un línea completa, es 
decir, lee caracteres hasta encontrar un '\n' y manda toda la línea 
directamente al procesador. 
 
 
Informática Industrial 2015/2016 7/7 Práctica 4 
 
 
informatica industrial/practicas/P5 - Clases abstractas y polimorfismo.pdf
	
 
 
 
 
 
 
 
Práctica	de	Informática	Industrial	I	
Grado	en	Ingeniería	en	Electrónica	Industrial	y	Automática	
2015‐2016
Práctica	5	
Clases	Abstractas	y	Polimorfismo 
 
 
 
 
Profesores: 
           Mohamed Abderrahim 
           Álvaro Castro González 
           Ioannis Douratsos  
           José Carlos Castillo 
           Javier Fernandez de Gorostiza 
          Juan Carlos González Victores 
 
Informática Industrial I 2015/2016 2/11 Práctica 5 
Práctica 5 – Clases abstractas y polimorfismo. 
Las clases abstractas están diseñadas para que sean clases padre y sean heredadas por clases hijas. Las 
clases abstractas presentan los métodos que se deben implementar en las clases hijas pero no se 
implementan, por lo tanto las clases abstractas no se pueden instanciar. Para instanciar una clase hija que 
hereda una abstracta, ésta debe implementar todos los métodos abstractos. 
En C++ las clases abstractas se declaran utilizando funciones miembro virtuales puras mediante la palabra 
reservada virtual. Una función miembro virtual pura es aquella que tiene que ser implementada en 
una clase derivada. Una clase abstracta es aquella que tiene al menos una función miembro virtual pura. 
 
class Operation { // abstract class 
  public: 
    virtual int method(int a, int b)=0; 
}; 
 
class Addition: public Operation { 
  public: 
    int method(int a, int b) {return a+b;} 
}; 
 
class Subtraction: public Operation { 
  public: 
    int method(int a, int b) {return a‐b;} 
}; 
 
int main() { 
  int n1, n2; 
  cout << "Introduce dos enteros:" << endl; 
  cin >> n1 >> n2; 
 
  Addition A; 
  Subtraction S; 
  cout << "Adding " << n1 << "+" << n2 << "=" << A.method(n1,n2) << endl; 
  cout << "Subtracting " << n1 << "‐" << n2 << "=" << S.method(n1,n2) << endl; 
 
  return 0; 
} 
 
Como se ha visto, las funciones miembro virtuales puras se declaran como una función virtual igualada a 
cero. 
Normalmente las funciones virtuales puras no se implementan en las clases abstractas pero podría hacerse 
si fuese estrictamente necesario. A continuación se muestra cómo sería y cómo se realiza la llamada a las 
funciones miembro implementadas. 
Informática Industrial I 2015/2016 3/11 Práctica 5 
 
... 
 
int Operation::method(int a, int b) { 
  cout << "Operandos " << a << " y " << b << endl; 
  return 0; 
} 
 
class Addition: public Operation { 
  public: 
    int method(int a, int b) { 
      Operation::method(a,b); 
      return a+b; 
    } 
}; 
 
... 
 
Las funciones abstractas puras hacen que no se puedan definir objetos de su clase. 
Definiendo los métodos de una clase base como virtual, permite que las clases derivadas sobrescriban los 
métodos de la clase base. Lo que hace es que la función que se llama se decida en tiempo de ejecución, 
esto es el enlazado dinámico. 
Atendiendo al siguiente código, fijarse en el distinto comportamiento de las funciones print y 
food¿Qué salida se esperaría del programa? ¿Por qué? 
 
#include <iostream> 
 
class Animal { 
  protected: 
    int age; 
  public: 
    Animal(){this‐>age=‐1;} 
    Animal(int n){this‐>age=n;} 
    virtual int getAge()=0; 
    virtual void print(){cout << "An animal " <<endl;} 
    void food() {cout << "not defined yet" << endl;}; 
}; 
 
class Aquatic : public Animal { 
  public: 
    Aquatic():Animal(0) {} 
    Aquatic(int nn):Animal(nn) {} 
    int getAge() { 
      return this‐>age; 
    } 
    void print() { 
      cout << "Aquatic Animal: " << this‐>age << " years old" << endl; 
    } 
    void food() { 
      cout << "little fishes and seaweeds" << endl; 
    } 
}; 
 
Informática Industrial I 2015/2016 4/11 Práctica 5 
 
 
int main() { 
  Aquatic*A = new Aquatic(11); 
  cout << "Aquatic:" <<endl; 
  A‐>print(); 
  A‐>food(); 
   
  Animal *animal = a; 
  cout << "Animal:" <<endl; 
  animal‐>print(); 
  animal‐>food(); 
 
  return 0; 
} 
 
El polimorfismo es el mecanismo por el cual un mismo método identificado por su nombre, se comporta 
de forma distinta dependiendo del tipo de objeto que lo invoque. Es decir, es la capacidad de un método 
de comportarse de diferente forma según el tipo de objeto que lo llama. En resumen, el polimorfismo 
permite que una serie de operaciones diferentes tengan el mismo nombre. 
Se verán tres formas de realizar el polimorfismo: 
1. Sobrecarga de métodos 
2. Sobrecarga de operadores 
3. Métodos virtuales 
Los dos primeros casos corresponden al polimorfismo estático, es decir, se decide en tiempo de 
compilación qué función va a ser llamada. El último caso corresponde al polimorfismo dinámico donde 
es en tiempo de ejecución cuando se decide la función a ejecutar. 
1. Sobrecarga de métodos 
Una forma habitual de lograr el polimorfismo es a través de la sobrecarga de funciones y operadores. La 
sobrecarga consiste en declarar varias funciones con el mismo nombre pero con diferentes parámetros de 
entrada, ya sea
en el númeroo en el tipo. El compilador utilizará la definición adecuada de la función 
dependiendo del tipo y del número de parámetros con los que se ha realizado la llamada a la función. 
Un ejemplo de esto se puede observar en los constructores del ejemplo anterior de los animales. Para 
crear instancias de la clase Aquatic se podrá realizar la llamada de dos formas diferentes: 
 
... 
 
Aquatic*A1 = new Aquatic(11); 
Aquatic*A2 = new Aquatic(); 
 
... 
 
Ejercicio 1 
Informática Industrial I 2015/2016 5/11 Práctica 5 
Utilizando el primer ejemplo de los operadores aritméticos, modificarlo para que las clases para que 
permitantambién sumar o restar tres números utilizando la función method. 
2. Sobrecarga de operadores 
La sobrecarga de operadores proporciona funcionalidad adicional a operadores de C++ como +, *, >=, 
+=, etc., cuando se aplican a tipos de datos definidos por el usuario. 
Siguiendo con el ejemplo de los animales, a continuación se presenta la sobrecarga de un operador unario 
y otro binario: 
 
... 
 
class Aquatic: public Animal { 
... 
    void operator ++(){this‐>age++;} //prefix 
    void operator ++(int){this‐>age++;} //postfix 
    bool operator>(Aquatic A) {return this‐>age > A.age;} 
}; 
 
... 
 
int main(){ 
  ... 
  Aquatic A1(1); 
  Aquatic A2(2); 
  cout << "A1 age:" << A1.getAge() << endl; 
  cout << "A2 age:" << A2.getAge() << endl; 
 
  if(A1> A2) { 
    cout << "A1>A2" << endl; 
  } 
  else { 
    cout << "A1<=A2" << endl; 
  } 
 
  ++A1; 
  A1++; 
 
  cout << "A1 age:" << A1.getAge() << endl; 
  cout << "A2 age:" << A2.getAge() << endl; 
 
  if(A1>A2) { 
    cout << "A1>A2 " << endl; 
  } 
  else { 
    cout << "A1<=A2 " << endl; 
  } 
  ... 
} 
 
Sin embargo, no todos los operadores pueden ser sobrecargados. Los siguientes no lo permiten: 
 
Informática Industrial I 2015/2016 6/11 Práctica 5 
Categoría del operador Operador 
Acceso a miembro 
Resolución de ámbito 
Condicional 
Puntero a miembro 
Tamaño de tipo de dato 
. (operator punto) 
:: (acceso global) 
?: (sentencia condicional) 
* 
sizeof(...) 
Ejercicio 2 
Utilizando el ejemplo de los animales, implementa la sobrecarga del operador >> para la clase Animal de 
tal forma que nos permita asignarle la edad. 
3. Métodos virtuales 
La definición de clases abstractas a través de métodos miembro virtuales permite la última forma de 
polimorfismo que se verá. Esto se ilustra en el siguiente ejemplo donde se determina qué operación se va 
a realizar en tiempo de ejecución. 
 
class Operation { 
  virtual int method(int a, int b)=0; 
}; 
 
class Addition: Operation { 
  public: 
    int method(int a, int b) {return a+b;} 
}; 
 
class Subtraction: Operation { 
  public: 
    int method(int a, int b) {return a‐b;} 
}; 
 
class Multiplication: public Operation { 
  public: 
    int method(int a, int b) {return a*b;} 
}; 
 
 
Informática Industrial I 2015/2016 7/11 Práctica 5 
 
int main() { 
  int n1, n2; 
  cout << "Introduce dos enteros:" <<endl; 
  cin >> n1 >> n2; 
 
  srand(time(NULL));     /* initialize random seed: */ 
  Operation *O; 
  switch(rand() % 3){ 
    case 0: O = new Addition; 
      cout << "Operation ADDITION" <<endl; 
      break; 
    case 1: O = new Subtraction; 
      cout << "Operation SUBTRACTION" <<endl; 
      break; 
    case 2:O = new Multiplication; 
      cout << "Operation MULTIPLICATION" <<endl; 
      break; 
  } 
  cout << "Result: " <<O‐>method(n1, n2) <<endl; 
} 
 
 
Informática Industrial I 2015/2016 8/11 Práctica 5 
Ejercicios 
 Continuando con la implementación del simulador de un ordenador que se empezó en la práctica 
anterior. Basándose en lo que ya se tenía, se van a realizar las pertinentes modificaciones para 
implementar el diagrama UML mostrado en el anexo junto a la descripción de cada una de las 
clases. 
 El programa principal deberá ser capaz de ejecutar el siguiente programa: 
 
int main() { 
  LineKeyboard LK("logitech"); 
  Uppercase UP("intel"); 
  Display D("lg"); 
  Input *I = &LK; 
  LK.connectTo(UP); 
  I‐>connectTo(UP); // do same as before line 
  UP.connectTo(D); 
  LK.process(); 
 
  CharKeyboard CK("logitech char");         
  Reverse R("intel reverse"); 
  Printer P("Ricoh"); 
  I = &CK; 
  (*I) >> R>>P; 
  I‐>process(); 
} 
 
Informática Industrial I 2015/2016 9/11 Práctica 5 
A continuación se da una descripción de todas las clases: 
 
Clase Métodos Descripción 
Device    Permanece igual que se definió. 
Input 
Input::Input(const string & name)  Inicializa un dispositivo de entrada con un nombre. 
Input::connectTo(Processor & P)  Conecta un dispositivo de entrada con un procesador. 
Processor Input::operator>>(Processor & P)  Conecta un dispositivo de entrada con un procesador. 
void Input::process()  Función virtual pura. 
Keyboard 
Keyboard::Keyboard(const string & name)  Inicializa un teclado con el nombre especificado. 
void Keyboard::process() 
Implementación por defecto de un teclado, lee una cadena de 
caracteres desde el teclado real utilizando el operador de flujo 
cin. Después manda esta cadena al procesador llamando al 
método process() del procesador al cual está conectado. 
CharKeyboard 
CharKeyboard::CharKeyboard(const string & name)  Inicializa un teclado de caracter con el nombre especificado. 
void CharKeyboard::process()  Igual que Keyboard::process() pero solo lee un carácter 
(para ello se puede utilizar la función estándarcin.get()). 
LineKeyboard 
LineKeyboard::LineKeyboard(const string & name)  Inicializa un teclado de línea con el nombre especificado. 
void LineKeyboard::process() 
Igual que Keyboard::process() pero lee un línea 
completa, es decir, lee caracteres hasta encontrar un '\n' y 
manda toda la línea directamente al procesador. 
Processor 
Processor::Processor(const string & name)  Inicializa un procesador con el nombre especificado. 
void Processor::connectTo(Output  & O)  Conecta el procesador con una salida. 
void Processor::process(const string & data) 
Función miembro virtual que se va a encargar de buscar 
algunos comandos especiales en los datos que le llegan como 
puede ser el comando “quit”. 
void Processor::process(const string & data, int n)  Lo mismo que la función anterior pero considerando sólo los n 
primeros caracteres. 
Output Processor::operator>>(Output & O)  Conecta un dispositivo de entrada con un procesador. 
Informática Industrial I 2015/2016 10/11 Práctica 5 
Uppercase 
Uppercase::Uppercase(const string & name)  Inicializa un procesador de mayúsculas con el nombre 
especificado. 
void Uppercase::process(const string & data) 
Convierte en mayúsculas toda la cadena de caracteres data y 
añade un prefijo “PROCESSED: ”. Manda el resultado al 
Display al cual está conectado. Por ejemplo, si data vale 
“hola”, la cadena enviada al Display debe ser 
“PROCESSED: HOLA”. 
void Uppercase::process(const string & data, int n)  Lo mismo que la función anterior pero considerando sólo los n 
primeros caracteres. 
Reverse 
Reverse::Reverse(const string & name)  Inicializa un procesador para invertir el orden de caracteres 
con el nombre especificado. 
void Reverse::process(const string & data) 
Invierte la cadena de caracteresdata y añade un prefijo 
“PROCESSED: ”. Manda el resultado al Displayal cual está 
conectado. Por ejemplo, si data vale “hola”, la cadena 
enviada al Displaydebe ser “PROCESSED: aloh”. 
void Reverse::process(const string & data, int n)  Lo mismo que la función anterior pero considerando sólo los n 
primeros caracteres. 
Output 
Output::Output(const string & name)  Inicializa un dispositivo de salida con el nombre especificado. 
void Output::process()  Función virtual pura. 
Display 
Display::Display(const string & name)  Inicializa una pantalla con el nombre especificado. 
void Display::process(const string & data)  Muestra la cadena en la pantalla utilizando cout. 
Printer 
Printer::Printer(const string & name)  Inicializa una impresora con el nombre especificado. 
void Printer::process(const string &
data) 
Simula la impresión de la cadena recibida mostrando por 
pantalla la cadena con el prefijo “Imprimiendo...”.Por 
ejemplo, si le llega la cadena “PROCESSED: aloh”, se 
imprimirá por pantalla utilizandocout la cadena 
“Imprimiendo... 
PROCESSED: aloh”. 
 
Informática Industrial I 2015/2016 11/11 Práctica 5 
 
informatica industrial/practicas/P6 - Plantillas.pdf
 
 
 
 
 
 
 
Práctica	de	Informática	Industrial	I	
Grado	en	Ingeniería	en	Electrónica	Industrial	y	Automática	
2015‐2016
Práctica	6	
Plantillas 
 
 
 
 
Profesores: 
           Mohamed Abderrahim 
           Álvaro Castro González 
           Ioannis Douratsos  
           José Carlos Castillo 
           Javier Fernandez de Gorostiza 
          Juan Carlos González Victores 
 
Informática Industrial I 2015/2016 2/6 Práctica 6 
Práctica 6 – Plantillas. 
Las plantillas es una de las características más poderosas y sofisticadas de C++. Las plantillas permiten 
crear funciones y clases genéricas que se pueden aplicar a distintos tipos de datos sin tener que modificar 
el código para cada tipo. 
1. Funciones genéricas 
Una función genérica es un conjunto de operaciones que se aplicarán a distintos tipos de datos. El tipo 
de dato sobre el que la función operará se pasa como parámetro. En esencia, cuando se crea una función 
genérica se está creando una función que se sobrecarga así misma automáticamente. 
Para definir una plantilla se utiliza la palabra reservada template y la forma general de definir una 
plantilla para una función es: 
 
template <class Type,...> return_type name_function(parameter list) { 
  //body of function 
} 
 
Type es una referencia al tipo de dato que se usará dentro de la función tanto para los parámetros de 
entrada como el de salida. El compilador lo sustituirá por el tipo de dato real que corresponda en cada 
llamada. 
A continuación se muestra un ejemplo en el que se crea una función genérica que intercambia los valores 
de dos variables. Puesto que el proceso para intercambiar dos valores es independiente del tipo de datos 
de las variables, es un ejemplo que se ajusta muy bien para el uso de plantillas. 
 
#include <iostream> 
 
using namespace std; 
 
template <class Type> 
void swaping(Type & a, Type & b){ 
  Type aux = a; 
  a = b; 
  b = aux; 
}; 
 
int main(int argc, char *argv[]) { 
  int i = 10, j = 20; 
  double x = 10.2, y = 43.11; 
  char a = 'v', b = 's'; 
 
  cout << "Original i, j: " << i << ' ' << j << '\n'; 
  cout << "Original x, y: " << x << ' ' << y << '\n'; 
  cout << "Original a, b: " << a << ' ' << b << '\n'; 
 
  swaping<int>(i,j); 
  swaping<double>(x,y); 
  swaping<char>(a,b); 
 
  cout << "Swaped i, j: " << i << ' ' << j << '\n'; 
Informática Industrial I 2015/2016 3/6 Práctica 6 
  cout << "Swaped x, y: " << x << ' ' << y << '\n'; 
  cout << "Swaped a, b: " << a << ' ' << b << '\n'; 
 
  return 0; 
} 
 
En este ejemplo, Type es el tipo genérico que representa el tipo de dato de los valores que serán 
intercambiados. El compilador lo sustituirá por int, double y char según cree las instancias necesarias de 
la plantilla de la función. 
¿Cuál es la salida? 
En una plantilla se pueden usar más de un tipo genérico de datos (de ahí los puntos suspensivos en la 
definición genérica de una plantilla de función). Implementa la función genérica que muestre los valores 
de dos variables de distintos tipos que se le pasan como parámetro. Prueba que funciona. La cabecera de 
la función genérica sería: 
 
... 
template<class tipo1, class tipo2> void print(tipo1 a, tipo2 b); 
... 
 
Recordando la práctica anterior, al igual que ocurre con las clases, las plantillas también se pueden 
sobrecargar. Además, también se pueden mezclar tipos de datos estándar con tipos genéricos de datos. 
Continuando con el último ejemplo implementa la función genérica que se corresponde con: 
 
... 
template<class tipo1, class tipo2> void print(tipo1 a, tipo2 b, double c); 
... 
 
¿Qué ocurre si ejecutas print(“cadena de texto”, 2.5, ‘a’);? ¿Por qué? 
Resumiendo, las funciones genéricas deben realizar la misma acción general para todas las versiones, sólo 
diferenciándose en el tipo de dato. En contraste, la sobrecarga de funciones “normales” permite que cada 
implementación se comporte de una forma completamente diferente. 
2. Clases genéricas 
Una clase genérica define todos los algoritmos que una clase va a usar y el tipo de dato que va a 
manipular se especificará como un parámetro cuando se instancie la clase. Una clase genérica es útil 
cuando usa una lógica que se puede generalizar. 
La forma general de definir una clase genérica es la siguiente: 
 
template <class Type,...> class class_name { 
  ... 
} 
 
Informática Industrial I 2015/2016 4/6 Práctica 6 
Lo mencionado sobre Type para funciones genéricas también aplica para clases genéricas. 
Para crear un objeto de la clase genérica se realiza de esta forma: 
 
class_name <type> object; 
 
Donde type es el tipo de dato que manejará la clase. A continuación se puede observar un ejemplo de la 
implementación de la estructura de datos pila funcionando con todo tipo de datos. ¿Hay algún error en el 
código anterior? Encuéntralo. 
 
#include <iostream> 
 
using namespace std; 
 
template<class Type> 
class Stack { 
    public: 
        Stack() : _size(10), _index(0) { // another way to initialize variables
            _data = new Type[_size]; 
        } 
        void push(Type data); 
        Type pop(); 
 
    private: 
        int _size, _index; // stack size 
        Type *_data; 
}; 
 
template<class Type> 
void Stack<Type>::push(Type data) { 
  if(_index == _size) { 
    cout << "Full stack" << endl; 
  } 
  else { 
    this‐>_index++; 
    this‐>_data[this‐>_index] = data; 
  } 
} 
 
template<class Type> 
Type Stack<Type>::pop() { 
  if(this‐>_index == 0) { 
    cout << "Empty stack" << endl; 
    return 0; 
  } 
  this‐>_index‐‐; 
  return this‐>_data[this‐>_index]; 
} 
 
int main() { 
  Stack<char> S; 
  S.pop(); 
  S.push('z'); 
Informática Industrial I 2015/2016 5/6 Práctica 6 
  S.push("q"); 
  S.push(2.1); 
} 
 
En la especificación de una plantilla de clase también se puede utilizar lo que normalmente se piensa que 
es un argumento estándar. Por ejemplo, en el ejemplo anterior, si quisiéramos que el tamaño de la pila 
pudiera definirse en la instanciación de un objeto de la plantilla de la clase se haría como sigue: 
 
... 
template<class T, int size> class Stack { 
  T data[_size]; 
} 
... 
 
¿Qué habría que cambiar en la implementación de las funciones miembro de la clase genérica? 
Nota: hay que tener en cuenta que en C++ sólo se permiten utilizar “argumentos estándar” en las 
plantillas de los tipos entero, puntero o referencia y son tratados como constantes. 
3. STL 
La Biblioteca de Plantillas Estándar (del inglés, Standar Template Library) de C++ es una biblioteca que 
proporciona clases de propósito general para implementar las estructuras de datos más conocidas y 
usadas. Están basadas en plantillas de clases y funciones. En la STL existen tres elementos principales: 
los contenedores que almacenan objetos, los algoritmos que actúan sobre los contenedores, y los 
iteradores que permiten recorrer los contenedores de diversas formas. 
Antes de desarrollar propias estructuras de datos y algoritmos (como se hizo con el ejemplo de la pila) 
asegurar que no se puede utilizar alguna de las STL ya existentes. Como ejemplo se va a ver como se 
trabaja con un vector de elementos y sus operaciones básicas. 
 
#include <iostream> 
#include <vector> 
#include <algorithm> 
 
using namespace std; 
 
int main() { 
  // creating vector with size 10 
    unsigned int i; 
  vector<char> myvector(10); 
  cout << "size = " << myvector.size() << endl; 
 
  // assign elements and showing 
  for(i=0;i<10;i++) { 
    myvector[i] = 'z' ‐ i; 
  } 
  for(i=0;i<myvector.size();i++) { 
    cout << myvector[i] << ' '; 
  } 
  cout << endl << endl; 
 
Informática Industrial I 2015/2016 6/6 Práctica
6 
  // add new elements if necessary 
  for(i=0;i<10;i++) { 
    myvector.push_back('z'‐i‐10); 
  } 
  for(i=0;i<myvector.size();i++) { 
    cout << myvector[i] << ' '; 
  } 
  cout << endl << endl; 
   
  // using an iterator 
  vector<char>::iterator it; 
  it = myvector.begin(); 
  while(it != myvector.end()) { 
    *it = toupper(*it); 
    it++; 
  } 
  for(i=0;i<myvector.size();i++) { 
    cout << myvector[i] << ' '; 
  } 
  cout << endl <<endl; 
 
  // sorting the vector 
  sort(myvector.begin(), myvector.end()); 
  for(i=0;i<myvector.size();i++) { 
    cout << myvector[i] << ' '; 
  } 
  cout << endl << endl; 
 
  cin.get(); // wait an INTRO 
 
  return 0; 
} 
 
Recordad: 
Es muy útil mientras se programa el autocompletado de código (Ctrl+Espacio), de este modo se podrán 
ver todas las posibilidades disponibles. 
Existen multitud de fuentes donde se puede encontrar más información sobre las STL. Por ejemplo se 
puede consultar cualquiera de los libros recomendados en la asignatura o alguno de los siguientes enlaces: 
 http://www.cplusplus.com/reference/stl/ 
 http://www.cppreference.com/wiki/stl/start 
Ejercicios 
Puesto que las plantillas se pueden aplicar prácticamente a cualquier tipo de dato, incluidos los definidos 
por uno mismo, aplicar lo aprendido al simulador de ordenador de las prácticas anteriores. 
Crear una lista de todas las cadenas que le llegan al procesador. Cuando le llegue la cadena history 
mostrar por pantalla el historial de todas las cadenas que haya recibido. 
 
informatica industrial/practicas/P7 - Ficheros.pdf
 
 
 
 
 
 
 
Práctica	de	Informática	Industrial	I	
Grado	en	Ingeniería	en	Electrónica	Industrial	y	Automática	
2015‐2016
Práctica	7	
Ficheros 
 
 
 
 
 
Profesores: 
           Mohamed Abderrahim 
           Álvaro Castro González 
           Ioannis Douratsos  
           José Carlos Castillo 
           Javier Fernandez de Gorostiza 
          Juan Carlos González Victores 
 
Informática Industrial I 2015/2016 2/6 Práctica 7 
Práctica 7 – Ficheros. 
1. Apertura y cierre de ficheros 
En esta práctica se verá cómo trabajar con ficheros del sistema. Hay que tener en cuenta que los ficheros 
de I/O (Input/Output) son simplemente un caso especial del sistema general de I/O del sistema y por lo 
tanto lo que se va a ver se puede aplicar también a cualquier otro flujo de datos conectado a otros tipos de 
dispositivos. 
Para trabajar con ficheros en C++ es necesario incluir el fichero de cabecea: fstream. 
Lo primero que hay que hacer para abrir un fichero es crear un flujo que dependerá de la “dirección” de 
los datos. Hay tres tipos de flujos: 
 De entrada: ifstream 
 De salida: ofstream 
 De entrada/salida: fstream 
Para abrir un fichero se llamará a la función open() o directamente mediante el constructor 
correspondiente. Esta función recibe como parámetros la ruta del fichero y el modo de apertura. El modo 
se determina con uno o más de estos valores: 
 ios::app → añadir datos al final del fichero. 
 ios::ate → posicionarse al final del fichero. 
 ios::in → determina un flujo de entrada. 
 ios::out → determina un flujo de salida. 
 ios::binary → modo binario (por defecto está el modo texto). 
 ios::trunc → cambia el tamaño del fichero a 0 eliminando los datos. 
Esta función tiene asignados varios valores por defecto, con lo que no estrictamente necesario ponerlos. 
A continuación se puede ver un ejemplo de uso: 
 
#include <iostream> 
#include <fstream> 
 
Using namespace std; 
 
int main(intargc, char *argv[]) { 
  ifstream input("input.txt"); //reading file in text mode 
  if(!input){ 
    cerr << "Error opening input file!" << endl; 
  } 
 
  ofstream output; 
  //writing file in binary mode 
  output.open("output.bin", ios::out | ios::binary); 
  if(output.is_open()) { //check if file is opened 
    cerr << "Output file ready" << endl; 
  } 
   
  // ... do things with files ... 
 
Informática Industrial I 2015/2016 3/6 Práctica 7 
  input.close(); 
  output.close(); 
 
  return 0; 
} 
 
2. Lectura y escritura de ficheros de texto 
Para leer y escribir ficheros de texto se pueden usar directamente los operadores >> y << respectivamente, 
igual que si se hiciera por consola. Por ejemplo se podría hacer algo como: 
 
output << “escribiendo en el flujo de salida output” << endl; 
 
Ejercicio 
Escribir un programa que pida al usuario el nombre y apellidos de varias personas y los escriba en un 
fichero usando una línea para los datos de cada persona. A continuación hacer otro programa que los 
lea y los muestre por pantalla. 
¿Cómo detectar el final del fichero? Se puede usar la función eof() (end of file) del flujo 
correspondiente o tener en cuenta que cuando se llega al final de fichero el flujo asociado devuelve 
false). 
Otra interesante función que permite la lectura de datos es getline() cuyos prototipos son: 
 
istream&getline(char *buf, streamsize num); 
istream&getline(char *buf, streamsize num, char delim); 
 
Estas funciones leen caracteres del flujo y los almacenan en el array apuntado por buf hasta que se haya 
leído num‐1 caracteres o hasta que se encuentra un final de línea (el carácter delim en la segunda forma) 
o hasta que se llegue al final de fichero. El carácter delimitador se extraerá y no se añadirá al array buf. 
La función get() tiene otras dos formas que funcionan de manera muy parecida a getline. Estos son 
los prototipos: 
 
istream & get(char *buf, streamsize num); 
istream & get(char *buf, streamsize num, char delim); 
intget(); 
 
La única diferencia entre las dos primeras formas y getline es que las formas de get no eliminan el 
delimitador y permanece en el flujo hasta la siguiente operación de lectura. En cuanto a get() devuelve 
el siguiente carácter y en caso de llegar al final de fichero devolverá EOF. 
Haz un programa que se encargue de leer el fichero que anteriormente has creado de nombres y los 
muestre por pantalla línea por línea. 
Informática Industrial I 2015/2016 4/6 Práctica 7 
3. Ficheros binarios 
Los ficheros de texto no son siempre los más eficaces. Además puede ser que se necesite escribir datos 
que no tienen formato, es decir, en crudo. Por estos motivos es necesario poder trabajar con ficheros 
binarios. 
Para trabajar con ficheros binarios es necesario abrir el fichero en el siguiente modo (ios::binary). 
Para leer y escribir un fichero binario se puede hacer byte a byte, usando las funciones get() y put(). O 
se puede hacer por bloques, usando las funciones read() y write().Que se encargan respectivamente 
de leer/escribir num caracteres desde la posición apuntada por buf. 
 
istream&read(char *buf, streamsizenum); 
ostream&write(char *buf, streamsizenum); 
 
Ejercicio 
Crear un programa que escriba carácter a carácter todos los caracteres del 0 al 255 en un fichero 
binario. Leer dicho fichero y mostrarlo por pantalla los números pares. 
4. Acceso aleatorio 
En C++ existen dos punteros asociados a los ficheros: uno es el puntero get, que apunta a la posición 
donde se va a realizar la siguiente operación de entrada (lectura), y el otro es el puntero put, que 
especifica la siguiente posición donde se realizará la próxima operación de salida (escritura). 
Para modificar estos punteros existen las funciones seekg y seekp: 
 
istream & seekg(off_type offset, seekdir origin); 
ostream & seekp(off_type offset, seekdir origin); 
 
Estas funciones desplazan sus respectivos punteros con un offset desde la posición indicada por 
origin, la cual puede ser uno de los siguientes valores: 
 ios::beg → el comienzo del fichero. 
 ios::cur → la posición actual. 
 ios::end → el final del fichero. 
Las operaciones de acceso aleatorio a un fichero generalmente sólo se utilizan en operaciones binarias y 
hay que ser especialmente cuidadoso puesto que puede provocar una falta de sincronización con los datos 
del fichero. 
Para determinar la posición actual de los punteros se usan las funciones: 
 
pos_typeseekg(); 
pos_typeseekp();
Cuyos resultados se pueden aplicar directamente a las funciones seekg y seekp de la siguiente manera: 
Informática Industrial I 2015/2016 5/6 Práctica 7 
 
istream & seekg(pos_type pos); 
istream & seekp(pos_type pos); 
 
Ejercicio 
Escribir un programa que guarde en formato binario los números enteros del 0 al 10 en un fichero. A 
continuación leerlos del fichero e imprimirlos por pantalla. Finalmente desplazar el puntero get del 
fichero un carácter desde el comienzo del fichero y volver a leerlos. ¿Qué resultado se obtiene? ¿Por 
qué? 
 
Informática Industrial I 2015/2016 6/6 Práctica 7 
Ejercicios 
Continuar ampliando la funcionalidad del simulador de ordenador. En este caso se deberá crear dos 
nuevas clases InputFile y OutputFile que heredarán de Input y Output respectivamente. 
InputFile se encargará de leer un fichero de texto y enviarlo al procesador correspondiente. A su vez 
crear otras dos clases que hereden de InputFile y que se comporten de forma diferente: una enviará los 
datos línea a línea y la otra palabra a palabra. 
OutputFile escribirá cadenas en un fichero de texto añadiéndolas al final. El formato de cada línea será 
[fecha+hora]:[cadena de texto]. 
Para obtener la fecha y la hora se podrá usar algo similar al siguiente código: 
 
#include <time.h> 
#include <string.h> // strtok: used to remove the line scape (‘\n’) 
 
... 
 
time_t rawtime; 
struct tm *timeinfo; 
time(&rawtime); 
timeinfo = localtime(&rawtime); 
cout << “TIME: “ << strtok(asctime(timeinfo), ”\n”) << endl; 
 
La salida en el fichero deberá ser algo parecido a lo siguiente: 
 
MonSep 06 18:39:05 2010:Processed by Uppercaseprocessor: EN 
MonSep 06 18:39:05 2010:Processed by Uppercaseprocessor: UN 
MonSep 06 18:39:05 2010:Processed by Uppercaseprocessor: LUGAR 
MonSep 06 18:39:05 2010:Processed by Uppercaseprocessor: DE 
MonSep 06 18:39:05 2010:Processed by Uppercaseprocessor: LA 
MonSep 06 18:39:05 2010:Processed by Uppercaseprocessor: MANCHA, 
MonSep 06 18:39:05 2010:Processed by Uppercaseprocessor: DE 
 
 
 
informatica industrial/problemas/ejerciciosII_v4.pdf
Ejercicios de Informática Industrial 
2014-2015 
 
1. Calcular el máximo de un array de números 
2. Calcular el factorial de un número. 
3. Ordenar un vector de números. 
4. Detectar cuando una palabra introducida es un palíndromo (se lee igual de izquierda a 
derecha, que de derecha a izquierda). Por ejemplo: Ana, arenera, oso, radar, 
reconocer, rotor, salas, seres, somos, sometemos,etc. 
5. Introducir dos matrices y multiplicarlas. 
6. Realizar un programa que nos detecte si los caracteres que introducimos son letras, 
números u otra cosa. 
7. Convertir una cadena de caracteres en minúscula a mayúscula. 
8. Escribir un programa que permita realizar distintas operaciones matemáticas sobre un 
par de números: sumar, restar, multiplicar, dividir, etc. El programa pedirá que se 
introduzcan los números con los que se va a operar así como la operación que se 
desea aplicar. Las funciones que implementan las operaciones tienen que estar 
implementadas en un fichero distinto de donde se encuentra la función main y deben 
contar además con el correspondiente fichero de cabecera. 
9. Realizar el mismo ejercicio que el anterior pero ahora los números para operar se le 
pasarán como parámetros al programa. 
10. Crear una estructura/clase que represente cada uno de los alumnos de la asignatura. 
Debe existir al menos los siguientes campos: nombre, apellidos, nie y nota. Crear un 
array/lista donde se vayan almacenando todos los alumnos para posteriormente 
calcular la nota media de todos; también se podrán listar los que tienen sobresaliente, 
notable, aprobado o suspenso. 
11. Hacer un programa que pida al usuario una cadena de caracteres y detecte si es o no 
un número entero, y, si lo es, que lo calcule. 
12. Lo mismo que el anterior, pero incluyendo la posibilidad de detectar números 
decimales. 
13. Difícil. Hacer un programa que almacene los nodos contiguos de una red, con las 
distancias entre ellos, y que calcule la ruta más rápida entre dos lugares. Se puede 
hacer con parte de la red de transportes de la Comunidad de Madrid. 
14. Hacer un programa que calcule si un número es primo o no, y que, si no lo es, lo 
descomponga en factores. 
15. Hacer un juego en el que, un tablero de diez por diez se llene aleatoriamente de unos y 
ceros. Luego, cada elemento mantendrá su valor (uno o cero) hasta la generación 
siguiente si más de dos tercios de sus vecinos son iguales a él, cambiará si menos de un 
tercio de sus vecinos son iguales a él, y tendrá un 50% de probabilidad de mantener su 
valor (y el restante 50% de cambiarlo) si entre un tercio y dos tercios de sus vecinos 
son iguales a él. Se mostrará por pantalla el valor de los elementos en forma de matriz. 
16. Sencillo. Hacer un programa que pida los elementos de una matriz, de tamaño 
prefijado, y que la muestre por pantalla. 
17. Lo mismo, pero con un tamaño de la matriz variable, que se pregunta previamente al 
usuario. 
18. Hacer un programa que detecte si un número de teléfono es fijo o móvil, y, si es fijo, 
que diga de qué provincia es (en una primera aproximación, se puede hacer que 
distinga si es de Barcelona, de Madrid, o de otra provincia). 
19. Sencillo. Hacer un programa que pida las dimensiones de un paralelepípedo, y a partir 
de ello, calcule su área y su volumen. 
20. Hacer un programa que pida el nombre, primer apellido y segundo apellido de un 
conjunto de personas, que los almacene, y que luego permita ordenarlos 
alfabéticamente por cualquiera de los tres campos, o sacar los que empiecen por una 
determinada letra de algún campo. 
21. Difícil. Lo mismo que el anterior, pero con un número variable de personas (memoria 
dinámica) y la posibilidad de encontrar cualquier cadena de caracteres en cualquier 
parte de cualquiera de los campos. 
22. Difícil. Hacer un programa que detecte rimas en un texto. 
23. Difícil. Hacer lo mismo que el anterior, pero además, contando sílabas. 
24. Hacer un programa que detecte tantos números como haya en un texto, reserve la 
memoria necesaria para ellos, los calcule como enteros y los guarde. 
25. La sucesión o serie de Fibonacci es la sucesión de números: 
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ... 
Cada número se calcula sumando los dos anteriores a él. 
• El 2 se calcula sumando (1+1) 
• Análogamente, el 3 es sólo (1+2), 
• Y el 5 es (2+3), 
• ….etc.. 
Realice un programa que cree un vector de números de Fibonacci e imprímalos por 
pantalla. Para crear el vector escriba una función fibonacci(x,y,v,n) 
Donde x e y son dos enteros que me indicarán los dos números iniciales del vector 
 v[0] = x v[1] = y 
Cada elemento del vector es la suma de los dos anteriores. 
v es el vector que vamos a crear y n el número de elementos del vector. 
26. Al programa anterior, añada una nueva función que ordene en forma decreciente los 
números del vector de Fibonacci creado e imprímalos por pantalla. 
27. Compruebe si un número entero positivo corresponde a un número de la serie de 
Fibonacci. Para esto use la fórmula de Binet: 
Si N es un número de Fibonacci entonces 5*N2+4 ó 5*N2-4 son cuadrados perfectos. 
28. Fácil: Escribir una función que acepta un límite superior y un límite inferior, calcular los 
cuadrados de cada uno de los números enteros entre el superior y el límite inferior 
[inclusive], y luego imprimir la suma de todas las cuadrados. Hacerlo a través de la 
recursividad. 
Eazy: Write a function to accept an upper and a lower limit, calculate the squares of each 
of the integer number between the upper and the lower limit [inclusive], and then print 
the sum of all the squares. Do so using recursion. 
29. Medio: Aceptar un número entero, junto con su base [binario, octal, decimal o 
hexadecimal], validar las entradas, a continuación, convertir el número en una base 
diferente, conforme a lo solicitado por el usuario, y luego imprimir el número de 
convertidos. 
Medium:
Accept an integer number along with its base [Binary, octal, decimal or 
hexadecimal], validate the inputs, then convert the number into a different base, as 
requested by the user, and then print the converted number. 
30. Difícil: Escribir una función para aceptar un número entero [hasta cinco dígitos], y 
imprimir el número de palabras. 
Eg: (a) 65 – Sixty Five. 
 (b) 12345 – Twelve Thousand Three Hundred and Forty Five. 
Difficult: Write a function to accept an integer number[Up to five digits long], and display 
the number in words. 
Eg: (a) 65 – Sixty Five. 
 (b) 12345 – Twelve Thousand Three Hundred and Forty Five. 
31. Difícil: Escribir un programa para aceptar cualquier fecha en el siglo 21 y la salida del 
día de la semana de esta fecha cae. Validar la entrada del número de días en un mes, 
año bisiesto, el número de meses en un año, etc. 
Difficult: Write a program to accept any date in the 21st century and output the day of the 
week this date falls on. Validate the input for number of days in a month, leap year, 
number of months in a year, etc. 
 
 
informatica industrial/problemas/Enunciado ejercicio UML.pdf
Ejercicio: 
 
Una biblioteca tiene copias de libros. Estos últimos se caracterizan por su nombre, tipo 
(ingeniería, literatura, informática, historia ...), editorial, año y autor. 
	
  
Los autores se caracterizan por su nombre, nacionalidad y fecha de nacimiento. 
	
  
Cada copia tiene un identificador, y puede estar en la biblioteca, prestada, con retraso o en 
reparación. 
	
  
Los lectores pueden tener un máximo de 3 libros en préstamo. 
	
  
Cada libro se presta un máximo de 30 días, y por cada día de retraso, se impone una 
“multa” de dos días sin posibilidad de coger un nuevo libro. 
	
  
Realiza un diagrama de clases y añade los métodos necesarios para realizar el préstamo y 
devolución de libros. 
informatica industrial/problemas/Mas ejercicios ingenieria del software resueltos.pdf
INFORMÁTICA INDUSTRIAL I 
Grado en Ingeniería Electrónica Industrial y Automática 
Ejercicios Ingeniería del Software 
Curso 2013-2014 
	
  
	
  
Ejercicio:	
  Venta	
  de	
  coches	
  
Realizar	
   el	
   diagrama	
   de	
   clases	
   correspondiente	
   al	
   siguiente	
   sistema.	
   Se	
   trata	
   de	
   una	
  
empresa	
  de	
  venta	
  de	
  coches	
  de	
  segunda	
  mano	
  con	
  las	
  siguientes	
  características:	
  
• Los	
   coches	
   los	
   suministran	
   distintos	
   proveedores,	
   nos	
   interesa	
   conocer	
   la	
  
marca,	
  modelo,	
  matrícula,	
   precio	
   de	
   compra,	
   de	
   venta.	
  Los	
   coches	
   pueden	
   ser	
  
turismos,	
  industriales	
  y	
  todoterrenos.	
  Además	
  pueden	
  necesitar	
  ser	
  reparados,	
  
por	
  lo	
  que	
  se	
  debe	
  tener	
  un	
  control	
  de	
  las	
  reparaciones	
  hechas,	
  que	
  pueden	
  ser	
  
mecánicas,	
  eléctricas	
  o	
  de	
  chapa.	
  
• En	
   la	
  empresa	
  habrá	
  dos	
   tipos	
  de	
  vendedores:	
   asalariados	
  y	
  por	
   comisión.	
  De	
  
los	
   asalariados	
   nos	
   interesa	
   saber	
   también	
   el	
   salario	
   y	
   de	
   los	
   que	
   van	
   con	
  
comisión	
   los	
   coches	
   que	
   se	
   han	
   venido.	
  Además	
   se	
   tendrá	
   un	
   control	
   de	
   los	
  
clientes	
   tanto	
  de	
   los	
  que	
  han	
  comprado	
  un	
  coche,	
   como	
  de	
   los	
   interesados	
  en	
  
algún	
  tipo	
  de	
  coche	
  que	
  podrán	
  hacer	
  reserva.	
  
• Los	
   coches	
   pueden	
   estar	
   en	
   distintas	
   exposiciones,	
   y	
   debemos	
   saber	
   en	
   todo	
  
momento	
  dónde	
  se	
  encuentra	
  cada	
  coche.	
  	
  
• Se	
  necesitan	
  operaciones	
  para	
  realizar	
  una	
  venta	
  de	
  un	
  coche,	
  para	
  reparar	
  los	
  
coches	
   que	
   los	
   necesiten,	
   etc.	
   También	
   interesa	
   tener	
   operaciones	
   que	
   nos	
  
devuelvan	
  qué	
   cliente	
   compró	
  un	
   cierto	
   coche,	
   que	
   se	
   realicen	
   listados	
  de	
   los	
  
coches	
  que	
  se	
  encuentran	
  en	
  stock	
  en	
  un	
  momento	
  dado.	
  
	
  
	
  
Ejercicio:	
  Distribución	
  de	
  productos	
  alimentarios	
  
Se	
   desea	
   realizar	
   la	
   gestión	
   de	
   un	
   negocio	
   de	
   distribución	
   de	
   productos	
   de	
  
alimentación.	
  Para	
  ello	
  se	
  pide:	
  
	
  
1.	
  Gestión	
  clientes	
  	
  
	
  
Los	
  clientes	
  pueden	
  ser	
  personas	
   jurídicas	
  o	
   físicas.	
  Los	
  datos	
  que	
   interesa	
  mantener	
  
de	
  los	
  clientes	
  son	
  un	
  código	
  único	
  de	
  cliente,	
  nombre,	
  dirección,	
  lista	
  de	
  teléfonos	
  de	
  
contacto	
  (con	
  su	
  descripción:	
  oficina,	
  almacén,…),	
  ciudad,	
  código	
  postal,	
  y	
  la	
  forma	
  de	
  
pago	
  (que	
  puede	
  ser	
  contado	
  o	
  crédito.	
  Las	
  personas	
  físicas	
  tienen	
  además	
  un	
  NIF	
  para	
  
identificarlas,	
  mientras	
  que	
   las	
  personas	
   jurídicas	
   cuentan	
   con	
  una	
   razón	
   social	
   y	
  un	
  
CIF.	
  
	
  Los	
  clientes	
  pueden	
  darse	
  de	
  alta,	
  modificarse	
  y	
  darse	
  de	
  baja.	
  	
  
	
  
2.	
  Gestión	
  de	
  proveedores	
  	
  
	
  
De	
   los	
  proveedores	
   interesa	
  mantener	
   los	
  siguientes	
  datos:	
  un	
  código	
  único,	
  nombre,	
  
dirección,	
   ciudad,	
   código	
   postal,	
   lista	
   de	
   teléfonos	
   de	
   contacto	
   (con	
   su	
   descripción:	
  
oficina,	
   almacén,	
   fax,…).	
   Los	
   proveedores	
   también	
   pueden	
   ser	
   personas	
   físicas,	
  
identificadas	
  por	
  su	
  NIF,	
  o	
  jurídicas,	
  identificadas	
  por	
  su	
  CIF	
  y	
  razón	
  social.	
  	
  
Los	
  proveedores	
  pueden	
  darse	
  de	
  alta,	
  modificarse	
  y	
  darse	
  de	
  baja.	
  	
  
	
  
3.	
  Gestión	
  de	
  artículos	
  	
  
	
  
Los	
   artículos	
   se	
   dividen	
   en	
   familias.	
   Cada	
   familia	
   se	
   caracteriza	
   por	
   un	
   código	
   y	
   una	
  
descripción.	
  	
  
Cada	
  artículo	
  se	
  compone	
  de	
  un	
  código,	
  nombre,	
  IVA	
  que	
  se	
  le	
  aplica,	
  precio,	
  número	
  
de	
  unidades	
  en	
  stock.	
  	
  
Cada	
  artículo	
  lo	
  sirve	
  un	
  único	
  proveedor.	
  	
  
Los	
  artículos	
  pueden	
  darse	
  de	
  alta,	
  modificarse	
  y	
  darse	
  de	
  baja.	
  	
  
	
  
4.	
  Gestión	
  de	
  albaranes	
  	
  
	
  
Un	
  albarán	
  estaría	
  formado	
  por	
  una	
  cabecera,	
  por	
  unas	
  líneas	
  de	
  albarán	
  y	
  por	
  un	
  pie	
  
con	
  los	
  totales.	
  	
  
La	
  cabecera	
  tiene	
  el	
  número	
  de	
  albarán,	
  los	
  datos	
  del	
  cliente	
  que	
  se	
  estimen	
  oportunos	
  
y	
  la	
  fecha	
  de	
  creación	
  del	
  albarán.	
  	
  
Cada	
   línea	
   del	
   albarán	
   consta	
   del	
   código	
   y	
   la	
   descripción	
   del	
   artículo,	
   el	
   número	
   de	
  
unidades,	
  el	
  precio	
  y	
  el	
  importe	
  total	
  del	
  artículo.	
  	
  
El	
  pie	
  recoge	
  los	
  totales	
  de	
  la	
  siguiente	
  forma:	
  Precio	
  de	
  los	
  artículos	
  sin	
  IVA	
  y	
  precio	
  
con	
  IVA.	
  	
  
De	
  un	
  albarán	
  debe	
  saberse	
  si	
  está	
  pagado	
  o	
  no.	
  	
  
Los	
  albaranes	
  pueden	
  crearse,	
  modificarse	
  y	
  borrarse.	
  	
  
	
  
	
  
	
  
informatica industrial/problemas/solución ejercicio UML.pdf
Ejercicio: 
 
Una biblioteca tiene copias de libros. Estos últimos se caracterizan por su nombre, tipo 
(ingeniería, literatura, informática, historia ...), editorial, año y autor. 
	
  
Los autores se caracterizan por su nombre, nacionalidad y fecha de nacimiento. 
	
  
Cada copia tiene un identificador, y puede estar en la biblioteca, prestada, con retraso o en 
reparación. 
	
  
Los lectores pueden tener un máximo de 3 libros en préstamo. 
	
  
Cada libro se presta un máximo de 30 días, y por cada día de retraso, se impone una 
“multa” de dos días sin

Continuar navegando