Análisis y Diseño de Algoritmos                                                                                                      

Prof: Ing. Victor Garro

Asistente: Marco Elizondo Vargas

 

PROGRAMACION EN C++

 

 

CAPITULO 12:  LAS CLASES EN VISUAL C

 

Dicen que vale mas una imagen que 1000 palabras, así que vamos a empezar directamente con un ejemplo:

 

Programa en C, con estructuras:

#include “stdio.h”

 

typedef struct

{ double x;

double y;

} Vector;

 

void SumarVector (Vector* v1, Vector* v2)

{

v1->x += v2->x;

v1->y += v2->y;

}

 

void ImprimirVector (Vector* v)

{

printf (“(%f,%f)”,v->x,v->y);

}

 

void main(void)

{

Vector a,b;

 

a.x = 1;

a.y = 2;

b.x = 8;

b.y = 10;

 

SumarVector (&a,&b);

ImprimirVector (&a);

}

 

 

Programa en C++, con clases:

#include “stdio.h”

 

class Vector

{

public:

double x;

double y ;

void Sumar (Vector* v2);

void Imprimir (void);

};

 

void Vector::Sumar (Vector* v2)

{

x += v2->x;

y += v2->y;

}

 

void Vector::Imprimir (void)

{

printf (“(%f,%f)”,x,y);

}

 

void main (void)

{

Vector a,b;

 

a.x = 1;

a.y = 2;

b.x = 8;

b.y = 10;

 

a.Sumar (&b);

a.Imprimir ();

}

Ambos programas son semejantes, hacen exactamente lo mismo. El primero usa las estructuras de C, y el segundo usa las clases de C++.

 

Una clase es básicamente un struct, que tiene además funciones declaradas. Una class tiene el concepto de campos públicos y privados: por defecto son privados, así que para que se comporte como un struct, hay que poner public: al principio, antes de los campos que vayamos a declarar.

 

Las funciones definidas dentro de una class tienen las siguientes particularidades:

 

-          Al implementarlas, hay que anteponer a su nombre el nombre de la clase y dos dos-puntos.

-          Para llamarlas, siempre hay que hacerlo referenciando una variable de la clase, como si fueran un campo normal.

-          Cuando en el interior de la funcion de una clase de usan los campos de la misma, se está accediendo en realidad a los campos de la variable que ha invocado a la función de la clase.

 

La función definida anteriormente y su llamada eran las siguientes:

void Vector::Sumar (Vector* v2)

  {

    x += v2->x;

    y += v2->y;

  }

 

void main (void)

  {

    Vector a,b;

 

    a.Sumar (&b);

  }

 

Mirado desde el punto de vista de C (intentando emular lo que hace C++) tendríamos lo siguiente:

void Vector_Sumar (Vector* this,Vector* v2)

  {

    this->x += v2->x;

    this->y += v2->y;

  }

 

void main (void)

  {

    Vector a,b;

 

    Vector_Sumar (&a,&b);

  }

 

En realidad, el parámetro this existe y se puede utilizar, pero no figura en la lista de parámetros, su declaración y envío son automáticos al invocar al método de la variable en cuestión.

 

 

El constructor y el destructor de una clase.

 

El constructor de una clase es una función que SE EJECUTA de forma automática al declarar una variable de la clase.

 

El destructor de una clase es una función que SE EJECUTA de forma automática al perder el ámbito una variable de una clase (al ser destruida).

En nuestra clase anterior, podríamos tener:

#include “stdio.h”

 

class Vector

  {

    public:

      double x;

      double y ;

      Vector ();                   // Constructor

      ~Vector ();                  // Destructor

      void Sumar (Vector* v2);

      void Imprimir (void);

  };

 

 

Vector::Vector ()

  {

    x = 0;

    y = 0;

  }

 

Vector::~Vector ()

  {

  }

 

void Vector::Sumar (Vector* v2)

  {

    x += v2->x;

    y += v2->y;

  }

 

void Vector::Imprimir (void)

  {

    printf (“(%f,%f)”,x,y);

  }

 

void main (void)

  {

    Vector a,b;

 

    a.x = 1;

    a.y = 2;

    b.x = 8;

    b.y = 10;

 

    a.Sumar (&b);

    a.Imprimir ();   

  }

 

Al declarar las variables a y b de tipo vector, se ejecuta el constructor para cada una de ellas, con lo cual después de declararlas podemos estar seguros de que a.x vale 0, al igual que a.y, b.x y b.y

 

En este caso, el destructor no hace nada, pero aquí podríamos poner código para destruir la variable.

 

Si el tipo fuera dinámico (tuviera que allocar memoria para funcionar) en el constructor podríamos los malloc correspondientes, y en el destructor los free correspondientes. De este modo, no tendríamos que llamar a una función Inicializar desde el programa principal, ni a una función Liberar antes de acabar.

 

Cuando se usan clases, en lugar de usar malloc y free se utilizar new y delete:

 

Vector* a;

a = new Vector;

. . . . . . .

delete a;

new Vector es semejante a malloc (sizeof(Vector)), pero además de allocar la memoria necesaria llama de forma automática al constructor.

 

delete a  es semejante a free (a), pero antes de llamar a free, se llama de forma automática al destructor.

 

 

Disponer de varios constructores:

#include “stdio.h”

 

class Vector

  {

    public:

      double x;

      double y ;

      Vector ();                   // Constructor

      Vector (int a, int b);       // Constructor

      ~Vector ();                  // Destructor

      void Sumar (Vector* v2);

      void Imprimir (void);

  };

 

 

Vector::Vector ()

  {

    x = 0;

    y = 0;

  }

 

Vector::Vector (int a, int b)

  {

    x = a;

    y = b;

  }

 

Vector::~Vector ()

  {

  }

 

void main (void)

  {

    Vector a,b;

    Vector z(10,9);

 

    // a y b son vectores que tienen de coordenadas 0 (constructor por defecto called)

    // z tiene como coordenadas 10,9 porque se ha llamado al constructor adecuado.

  }

 

 

Conclusiones.

Todo esto no ha hecho más que empezar. Aquí está la información mínima para EMPEZAR A ENTENDER lo que es la orientación al objeto y las clases en C++. Sin embargo, para empezar a hacer alguna cosa es suficiente, y enseguida se notarán las mejoras en los diseños si se aplica con sentido común.

 

Es importante entender que ya no se habla de:  “..... una función SumarVector que recibe dos punteros a vector y le suma al primero el segundo.....”, sino que se habla de: “..... la clase Vector tiene un método Sumar, que permite sumar al vector otro que se le pasa por parámetro.... “. No tenemos funciones, sino métodos de clases.

 

 

 

 

 

Beneficios de uso de clases

 

1)       Quedan perfectamente definidas las estructuras: están claros sus datos y sus operaciones.

 

2)      Los programas no pueden acceder a los miembros internos de las estructuras, solo a las operaciones (siempre que se pongan en el apartado private:).

 

3)      No hay conflictos entre nombres de funciones: una clase Vector puede tener la operación Imprimir, y una clase Matriz puede tener la operación Imprimir, y no hay problema, ya que una se llama Vector::Imprimir (invocada por una variable de tipo Vector, y la otra se llama Matriz::Imprimir (invocada por una variable de tipo Matriz).

 

4)      Mediante sobrecarga de operadores y otras técnicas más complejas, podemos escribir programas como el siguiente:

void main (void)

  {

    Matriz a,b,c;

 

    a.Llenar ();

    b.Llenar ();

    c = a + b;        // Sobrecarga del operador +, para sumar matrices.

    c.Imprimir ();

  }

 

5)      La implementación de una clase queda totalmente oculta a los programas y a otras clases que las puedan usar, y esto permite cambiar la implementación, con el único cuidado de conservar las cabeceras de las operaciones definidas, pudiendo añadir nuevas. C++ tiene incluso declaración de parámetros con valores por defecto, de tal modo que si se usa una función y no se le envía ese parámetro, tomará el valor por defecto.

 

6)      Mediante capas de transformación de entorno, estas clases de pueden usar en diferentes plataformas. Las capas de transformación no han de hacer otra cosa que adaptar los formatos de las llamadas para que todo sea correcto, pero en ningún caso cambiar ni manipular la implementación.

 

7)      Conseguimos hacer código que sea:

-          Fácil de diseñar. (Obliga a diseñar antes de empezar a programar).

-          Fácil de entender. (Sabemos donde encontrar las cosas).

-          Fácil de modificar. (Se puede modificar la implementación y mantener la definición)

-          Seguro de usar. (Se pueden incorporar tratamientos de errores internos).

-          Escalable (mediante la herencia y el polimorfismo de clases).

 

 

 

 

 

Free Web Hosting