miércoles, 18 de enero de 2012

Otro ejemplo de TAD

En este post tenemos un ejemplo de TAD con su código fuente completo debidamente comentado para que podáis copiarlo y usarlo sin problemas y así comprender mejor su funcionamiento. Cualquier duda o cosa que queráis no dudéis en ponerla en los comentarios.

/*************************************************/
/* Interfaz del módulo */
/*************************************************/

#pragma once
/********************************
Definicion del tipo abstracto
********************************/
/*
TAD: Tipo abstracto de datos-->
Agrupacion de
  una coleccion de valores
  +
  operaciones de manipulacion */
/******************************/


typedef struct TPunto {
void Leer();
void Escribir();
float Distancia(TPunto p );
/*OCULTACION DE INFORMACION */
 private:
  float x;
  float y;

};


================================================================
================================================================
================================================================

#include <stdio.h>
#include <math.h>
#include "mod.h"

/******************************/
/* Implementacion del tipo abstracto */
/******************************/


void TPunto::Leer()
{

printf("Dame las coordenadas del punto (x,y)");
scanf(" (%g , %g)", &x, &y);
}

void TPunto::Escribir(){
printf(" (%g , %g)", x, y);
}


float  TPunto::Distancia (TPunto p){
float dis_x, dis_y;

dis_x= x-p.x;
dis_y= y-p.y;

return sqrt (dis_x*dis_x + dis_y*dis_y);
}


================================================================
================================================================
================================================================
#include <stdio.h>
#include "mod.h"

int main(){
 TPunto a, b;
 a.Leer();
 b.Leer();

 printf(" Veamos lo leido \n");
 a.Escribir();
 b.Escribir();


 printf("\n distancia = %g \n", a.Distancia(b));

domingo, 8 de enero de 2012

Módulos en programación

En programación un módulo es un fragmento de programa utilizado en algún momento para la construcción del programa completo y podemos definirlo como fragmento de programa desarrollado de forma independiente.

El concepto de módulo, está íntimamente ligado a la idea de abstracción. Un módulo debe definir un elemento abstracto y debe ser usado desde fuera con sólo saber qué hace el módulo, pero sin necesidad de conocer cómo lo hace.

Especificación y realización:

          La especificación del módulo es todo lo que se necesita para poder usar los elementos definidos en él. Esta especificación constituye la interfaz. La ocultación consiste en que el programa que usa un elemento de un módulo sólo tiene visible la información de la interfaz, pero no la realización.

Compilación separada:

          El programa está formado por varios ficheros fuente, cada uno de los cuales se compila por separado.

Compilación segura:

          Al compilar un fichero fuente el compilador comprueba que el uso de elementos de otros módulos es consistente con la interfaz.

Ocultación:

          Al compilar un fichero fuente el compilador no usa información de los detalles de realización de los elementos de otros módulos.

Descomposición modular:

          La posibilidad de compilar módulos de forma separada permite repartir el trabajo de desarrollo de un programa, a base de realizar su descomposición modular.

El acoplamiento entre módulos indica cuántos elementos distintos o características de uno o varios módulos han de ser tenidos en cuenta a la vez al usar un módulo desde otro. Este acoplamiento debe reducirse a un mínimo.

          La cohesión indica el grado de relación que existe entre los distintos elemento de un mismo módulo, y debe ser lo mayor posible. Esto quiere decir que dos elementos íntimamente relacionados deberían ser definidos en el mismo módulo, y que un mismo módulo no debe incluir elementos sin relación entre sí.

Módulos en C+-:

          Un programa descompuesto en módulos se escribe como un conjunto de ficheros fuente relacionados entre sí, y que pueden compilarse por separado. Cada fichero fuente constituye así una unidad de compilación.

Proceso de compilación simple:

          Un fichero fuente es un fichero de texto que contiene el código de uan unidad de compilación, es decir, es posible invocar el compilador dándole como entrada sólo ese fichero fuente. La compilación de un fichero fuente produce un fichero objeto que contiene la traducción del código C+- a instrucciones de máquina, los ficheros fuente en C+- tienen la extensión .cpp y los ficheros objeto la extensión .o.

Módulo principal:

          Cuando se descompone un programa en C+- en varios módulos uno de ellos ha de ser el programa principal o módulo principal. Este módulo será el que contenga la función main().

Módulos no principales:

          Los módulos de la aplicación que no contienen una función main() no permiten generar un programa ejecutable por sí solos. Los elementos que contienen están destinados a ser usados por el programa principal u otros módulos.

La distinción entre los elementos públicos y los privados se hace repartiendo el código del módulo en dos ficheros fuente separados: un fichero de interfaz o fichero de cabecera y un fichero de implementación.

          El fichero de interfaz tendrá la extensión .h y el de implementación la extensión .cpp.

          La directiva #include sirve para hacer referencia a un fichero fuente desde otro, y tiene como parámetro el nombre del fichero físico incluyendo la extensión.

Uso de módulos:

          Para usar los elemento públicos definidos en un módulo hay que incluir la interfaz de ese módulo en el código donde se vaya a utilizar,. Esto se consigue con la directiva #include. La novedad ahora es que los nombres de los ficheros de la propia aplicación debes escribirse entre comillas “ “ y no entre ángulos < >.

Declaración y definición de elementos públicos:

          En la declaración de un elemento hay que especificar lo necesario para el compilador pueda compilar correctamente el código que usa dicho elemento. En la definición de un elemento hay que especificar lo necesario para que el compilador genera el código del propio elemento.

          Los tipos y constantes se especifican totalmente en el fichero interfaz. No hay declaración y definición separadas. Las variables se definen de la manera habitual en el fichero de implementación, incluyendo la especificación de valor inicial en su caso. Con ello el compilador reserva espacio para dicha variable en el módulo que la define. En el fichero interfaz se pone además una declaración que indica el tipo y nombre de la variable, sin indicar el valor inicial, y precedida de la palabra clave extern. Esta declaración permite al compilador generar código de las sentencias que usan dicha variable en otros módulos sin reservar espacio para ella, ya que formará parte efectiva del código del módulo que la define. La conexión entre las referencias a la variable y su ubicación real se resuelve durante la fase de montaje, posterior a la compilación. Los subprogramas se definen de la manera habitual en el fichero de implementación y permiten al compilador generar el código objeto del subprograma. En el fichero de interfaz se pone además una declaración en forma de prototipo o cabecera de subprograma sólo con el tipo, nombre y argumentos. Esta cabecera permite al compilador generar el código de las sentencias de llamada al subprograma. La conexión entre las llamadas al subprograma y su código real se resuelve durante la fase de montaje, posterior a la compilación.

Conflicto de nombre en el ámbito global:

          Es posible especificar elementos en el ámbito más externo que sólo sean visibles en el fichero fuente donde se definen. Para ello basta poner la palabra clave static delante de la definición del elemento.

Unidades de compilación en C+-:

          El módulo principal: programa.cpp

          El fichero de interfaz de un módulo: modulo.h

          El fichero de implementación de un módulo: modulo.cpp

Implementación de abstracciones como módulos:

          En la mayoría de los casos los tipos abstractos de datos identificados en una aplicación son buenos candidatos para ser codificados como módulos independientes, y lo mismo ocurre con las abstracciones funcionales de cierta complejidad. Por lo tanto el desarrollo basado en abstracciones lleva implícita una posible descomposición natural del programa en módulos.

Dependencias entre ficheros:

          Las relaciones de uso entre módulos se corresponden, en principio, con las directivas #include usadas en un fichero fuente para hacer visibles los elementos de otro, y que pueden aparecer en el fichero .cpp y/o en el .h.

          Debemos tener cuidado pues si no se toman precauciones el preprocesador incluirá el código dos veces y se tendrán errores por duplicación. La directiva #pragma once sirve para evitar duplicidades.

La modificación del código de un programa para reorganizarlo sin cambiar su funcionalidad se denomina refactorización.

Reutilización de módulos:

          Los módulos que definen abstracciones relacionadas entre sí pueden agruparse en una biblioteca o librería que se pone a disposición de quienes desarrollan aplicaciones en un campo determinado

martes, 3 de enero de 2012

Ejemplo de TAD

Aquí os dejo un ejemplo de tipo abastracto de dato TAD, espero que os sirva. Está todo el código fuente y compila perfectamente, sólo tenéis que copiarlo y listo:

Fichero Interfaz hola.h

#pragma once
typedef struct TipoModulo1{
  void ImprimirHola();
};


Fichero Implementación hola.cpp

#include <stdio.h>
#include "interfaz.h"

void TipoModulo1::ImprimirHola(){
  printf("Hola");
}


Fichero Principal HolaMundo.cpp

#include <stdio.h>
#include "interfaz.h"

TipoModulo1 Modulo1;
int main(){
  Modulo1.ImprimirHola();
}

Tipos Abstractos de datos TAD

Un tipo abstracto de datos (TAD) es una agrupación de una colección de valores y una colección de operaciones de manipulación, podemos definirlos de varias maneras:

Definición de tipos abstractos como tipos registro (struct):

          Los campos de datos sirven para almacenar el contenido de información del dato abstracto, los subprogramas permiten definir operaciones sobre esos datos, la posibilidad de declarar ciertos elementos como privados permite ocultar detalles de implementación, y dejar visible sólo la interfaz del tipo abstracto.

Ocultación:

          Para que un tipo sea realmente abstracto haría falta que los detalles de implementación no fueran visibles. Para permitir esta ocultación los tipos struct admiten la posibilidad de declarar ciertos elementos componentes como privados, usando la palabra clave prívate para delimitar una zona de declaraciones privadas dentro de la estructura.

Desarrollo por refinamiento basado en abstracciones:

          Para realizar un refinamiento basado en abstracciones podemos considerar el dato como un dato elemental, y usar directamente un tipo predefinido del lenguaje para representarlo, considerar el dato como un dato complejo, y descomponerlo en otros más sencillos (como registro, unión o formación), considerar el dato como un dato abstracto y especificar su interfaz, dejando para más adelante los detalles de su implementación.