lunes, 12 de octubre de 2015

Clases Abstractas y Asignación dinamica de memoria

Programacion Orientada a Objetos


CLASES ABSTRACTAS
Estas clases se caracterizan por tener algunos de sus métodos declarados como abstractos, pero ¿qué es un método abstracto?. Un método abstracto es aquel que está definido, pero no tiene cuerpo, es decir, le declaramos el nombre, los parámetros y el tipo de devolución pero no le declaramos lo que va entre llaves "{}", es más, no le ponemos llaves.

Estas clases se utilizan para permitir que otras clases hereden de ella y proporcionar un modelo a seguir.

La declaración de una clase y método abstracto es el siguiente:

Public abstract class nombreClase{
public abstract tipo nombre(argumentos (si los lleva));
}

Reglas básicas de este tipo de clases:
Como ya he mencionado, una clase se declara abstracta si tiene algún método abstracto.
Una clase abstracta no puede crear objetos, es decir, no podemos utilizar "new" para una clase abstracta, ya que tiene métodos que no están definidos.
Una clase abstracta no puede ser a la vez "final".
Si una clase hereda de una clase abstracta, deberá de sobreescribir todos los métodos abstractos, si no es así, la clase que hereda deberá ser pasada a abstracta.
Una clase abstracta puede llevar métodos NO abstractos, pero solo con que exista un método abstracto, la clase deberá ser pasada a abstracta.
Como los métodos estáticos no pueden ser redefinidos, un método abstracto no puede ser estático.
Una clase abstracta si puede tener constructores. Como sabemos, no es posible crear objetos de una clase abstracta, pero de una clase, la cual herede de una clase abstracta, si se pueden crear objetos, y como sabemos cuando creamos un objeto de una clase que hereda, la primera llamada de su constructor es una llamada al constructor de la clase "padre", lo que permite que aunque no cree un objeto, si se pueda utilizar su constructor.

Este Tipo de Clases nos permiten crear “método generales”, que recrean un comportamiento común, pero sin especificar cómo lo hacen. A nivel de  código tienen por particularidad que algunos de sus métodos no tienen “cuerpo de declaración”, ¿qué quiere decir esto? no tienen las llaves { } ni código dentro de ellos y deben estar precedidos por la palabra clave abstract. Si una clases contiene uno o más métodos abstractos está clase debe ser abstracta. Estas clases como son generalidades no pueden ser instanciadas por ningún objeto (se dice que su nivel de abstracción es demasiado alto), entonces su único fin es ser heredado/extendido por otras clases.

Ejemplo

public abstract class Figura {

    // Atributos:
    public int numeroLados;
    public int area;
    public int volumen;

    // Métodos:
    abstract public void calcularArea();
    abstract public void calcularVolumen();
}
En este poco original ejemplo se puede apreciar que toda figura tiene un método para calcular su Área y Volumen.





Pongamos un ejemplo:


 

















Bien, en esta clase abstracta tenemos:

Un atributo de tipo "String" llamado "color".
Un constructor al cual le pasamos un parámetro de tipo "String".
2 métodos abstractos.
Un método NO abstracto


Creamos una clase llamada cuadrado que herede de Figura la cual posee:

2 atributos "x" e "y".
Un constructor al cual le pasamos 3 parámetros.
Una llamada al constructor de la superclase "Figura", la cual, como le pusimos un parámetro, a super() le tenemos que pasar un parámetro.
Los 2 métodos heredados, a los cuales les damos cuerpo.





















Creamos una clase Círculo que herede de figura, la cual posee lo siguiente:

Un atributo.
Un constructor con parámetros.
Una llamada al constructor de la superclase "Figura" a la cual le pasamos el parámetro correspondiente.
Los 2 métodos heredados de "Figura" con cuerpo.




Bien en esta última clase realizamos un pequeño menú con los bucles "SWITCH" y "DO/WHILE".
Comenzamos introduciendo una opción, por ejemplo 1.
El switch nos manda a la opción "case 1". En ella se nos pide el radio y el color del futuro Circulo.
Una vez introducido los datos que nos pide, creamos un objeto de la clase Circulo, al cual le pasamos  los parámetros que nos pide. Cabe mencionar, que como ya dijimos, no es posible crear un objeto de la clase "Figura" ya que es una clase abstracta, pero con la ayuda del polimorfismo podemos crear un objeto de la clase Circulo y así poder utilizar atributos y métodos de la clase "Figura"
Figura f=new Figura();// Esto nos da error
Figura f=new Circulo();//Esto está bien.
Nos imprime por pantalla el área, el perímetro y el color.
Tras esto, nos vuelve aparecer el menú para crear otro objeto, o para salir de la aplicación, en cuyo caso no volverá a aparecer el menú.


ASIGNACION DINAMICA DE MEMORIA

Es la asignación de almacenamiento de memoria para utilización por parte de un programa de computador durante el tiempo de ejecución de ese programa. Es una manera de distribuir la propiedad de recursos de memoria limitada entre muchas piezas de código y datos. Un objeto asignado dinámicamente permanece asignado hasta que es desasignado explícitamente, o por el programador o por un recolector de basura; esto es notablemente diferente de la asignación automática de memoria y de la asignación estática de memoria. Se dice que tal objeto tiene tiempo de vida dinámico.

Otra de las grandes ventajas de la utilización de punteros es la posibilidad de realizar una asiganación dinámica de memoria. Esto significa que la reserva de memoria se realiza dinámicamente en tiempo de ejecución, no siendo necesario entonces tener que especificar en la declaración de variables la cantidad de memoria que se va a requerir. La reserva de memoria dinámica añade una gran flexibilidad  a los programas porque permite al programador la posibilidad de reservar la cantidad de memoria exacta en el preciso instante en el que se necesite, sin tener que realizar una reserva por exceso en prevención a la que pueda llegar a necesitar.
 
 Dado que los punteros se pueden aplicar a cualquier tipo de variable se puede entonces realizar una asignación de memoria dinámica para cualquier variable. La función malloc es la que se utiliza para realizar una reserva de memoria y se encuentra en el archivo de cabecera <stdlib.h>.

La memoria dinámica es un espacio de almacenamiento que se puede solicitar en tiempo de ejecución. Además de solicitar espacios de almacenamiento, también podemos liberarlos (en tiempo de ejecución) cuando dejemos de necesitarlos.

Para realizar esta administración de la memoria dinámica, C++ cuenta con dos operadores new y delete. Antes de utilizarlos, debemos incluir el encabezado <new>.

El operador new reserva memoria dinámica de cualquier tipo, esto es:

tipos primitivos (int, double, etc)
tipos definidos por el usuario (clases o estructuras).
Veamos las siguientes líneas:

int *ptrEntero;
ptrEntero = new int;
/*(al puntero ptrEntero le asignamos
dinamicamente espacio para contener un valor int)*/


int *ptrEnteroA;
ptrEnteroA = new int(5);
/*(igual que al anterior
pero de paso lo inicializamos en 5)*/





También podríamos hacerlo con un arreglo, para esto:

int *arreglo =  new int[45];
/*
(creamos un arreglo dinámico, ésta vez lo
hacemos en la misma línea en la que
declaramos el puntero)
*/

Supongamos ahora que poseemos una clase Punto, podríamos crear objetos dinámicos a partir de esta clase.

Punto *ptrQ;
ptrQ = new Punto(4,5);
/*
(en la segunda línea le pasamos
además dos parámetros separados por
coma al constructor de Punto)
*/

Hemos estado pidiendo memoria dinámica, una vez utilizada lo correcto sería liberarla antes de que finalice el programa para esto utilizaremos el operador delete:

delete ptrEntero;
delete ptrEnteroA;
delete ptrQ;
delete [] arreglo;
//Si no usaramos [] no se liberaría el arreglo entero


programa, con una sencilla clase Punto, y la declaración de algunos objetos en la memoria dinámica.

#include <iostream>
using std::cout;

using std::endl;
#include <new> //para poder utilizar new y delete
class Punto

{
 public:
  Punto(int X=0,int Y=0)

    {
      establecer(X,Y);
    }
  void establecer(int x1,int y1)

  {
    x = x1;
    y = y1;

  }
  void imprimir(void)
  {
    cout << "(" << x << "," << y << ")" << endl;

  }
 private:
  int x;
  int y;

};

int main()
{
  //declaracion e inicializacion
  Punto J(45,-12);

  Punto *ptrQ;
  ptrQ = new Punto(5,7);

  Punto *arreglodePuntos;
  arreglodePuntos = new Punto[10];

  //imprimimos
  cout << "J";
  J.imprimir();

  cout << "ptrQ";
  ptrQ->imprimir();
  for (int i = 0 ; i < 10 ; i++)

    {
      cout << "arreglodePuntos[" << i <<"]";
      arreglodePuntos[i].imprimir();

    }
  //liberamos
  delete ptrQ;
  delete [] arreglodePuntos;

  //fin
  return 0;
}


No hay comentarios:

Publicar un comentario