Anuncios

Bienvenidos sean a este post, ha pasado mucho tiempo de mi ultimo post. Me tome un pequeño respiro que necesitaba dado que nunca pude aprender C++ y fue mucha informacion de golpe, :). Ahora vamos con lo que creo es una piedras fundamentales de este lenguaje, los objetos y las clases. Vamos a empezar con las clases.

Anuncios

Las clases se utilizan para declarar nuevos tipos de variables o tambien puede ser utilizada para guardar algunos tipos de datos y funciones que se usaran para ese tipo de clase, en el libro de donde saco para este blog, citaba 2 ejemplos: uno con un auto y otro con un gato. Con el auto lo que trata de decirnos que AUTO es una clase y que dicha clase esta compuesta por las variables Puerta, Motor, Ruedas, etc. y a su vez hay funciones que en el auto para el conductor son invincibles (p.e. el Motor) y tambien tenes variables que permiten el conocimiento de la clase (combustible) y tambien ayudan al funcionamiento del Motor (Combustible, Agua, Aceite, etc). Por otro lado, tambien citan a la clase Gato. En esta se estudian algunas variables propias de el y algunas “funciones” que puede realizar. Las clases son privadas por defecto, pero estas pueden ser publicas o privadas, si son privadas todas la informacion declarada dentro de la misma no puede ser utilizada por el programa, pero en caso de que se declaren como públicas las variables pasan a ser accesibles para todo el programa. Lo ideal seria lograr un equilibrio que cierta informacion no se adquirida en cualquier parte del programa pero que si tenga algun metodo indirecto para poder adquirir o modificar los mismos atraves de una declaracion pública. Una estructura de clase seria de la siguiente forma:

class Nombre_de_la_clase
{
public:
    variables,funciones,etc…
private:
    variables,funciones,etc…
}; 
Anuncios

Como notaran este es un metodo para declarar la parte publica (public) que lo hara hasta que se encuentre la parte privada (private) o el fin de la clase (lo que suceda primero) y como detalle, al final de la ultima llave que cierra la clase va un punto y coma (;).

Anuncios

Ahora vamos a otra parte cuando se invoca a la clase se le asigna un objeto (es el nombre que va a tener de ahora en mas la clase) y luego desde ese objeto se llaman a los metodos contenidos en la clase (metodos = funciones). Veamos un ejemplo que luego desarrollaremos:

Gato Pelusa;  // A la clase Gato se le asigna el objeto Pelusa.
Pelusa.Maullar(); // Y a Pelusa se la hace ejecutar el metodo Maullar.
Anuncios

La definicion de los metodos de una clase en un programa se efectua con 2 veces dos puntos (::) entre el nombre de la clase y el nombre del metodo, un ejemplo:

void Gato::Maullar() { ….. }
Anuncios

Es muy parecido a como cuando se declaran funciones pero con la diferencia que en vez de llevar solamente el nombre se pone el nombre de la clase :: el nombre de metodo declarado en la misma, para verlo mas claramente les voy a dar un ejemplo con todo esto:

clase00.cpp

# include <iostream>

using namespace std;

class Gato
{
public:
        int ObtenerEdad();
        void AsignarEdad(int edad);
        void Maullar();

private:
        int suEdad;
};

int Gato::ObtenerEdad()
{
        return suEdad;
}

void Gato::AsignarEdad(int edad)
{
        suEdad = edad;
}

void Gato::Maullar()
{
        cout << "Miau!\n";
}

int main()
{
        Gato Pelusa;
        Pelusa.AsignarEdad(5);
        Pelusa.Maullar();
        cout << "Pelusa es un gato que tiene ";
        cout << Pelusa.ObtenerEdad() << " años de edad.\n";
        Pelusa.Maullar();
        return 0;
}
Anuncios

Vamos a analizar este ejemplo, primero definiremos nuestra clase llamada Gato, en la seccion publica tendremos tres prototipos:

int ObtenerEdad();     
void AsignarEdad(int edad);
void Maullar();
Anuncios

Estos tres prototipos seran los tres metodos disponibles por nuestra clase, de los cuales hablaremos mas adelante, pasemos a la seccion privada, en ella declararemos una variable llamada suEdad para almacenar la de edad de nuestro gato, con esto terminamos nuestra clase ahora pasemos a explicar los tres metodos definidos posteriormente, veamos el primer metodo:

int Gato::ObtenerEdad()
{
    return suEdad;
}
Anuncios

Como pueden ver se define igual que las funciones vistas anterioremente pero con la salvedad que debemos indicar a que clase pertenece, es decir primero va el tipo de variable, luego el nombre de la clase unido por medio de los dos puntos (::), el nombre del metodo, luego como todas las funciones, partentesis, variables en caso de ser necesario, bloque entre llaves ({}) y por ultimo instrucciones entre las mismas, este metodo en particular nos permitira tener acceso a la variable declarada en la parte privada y poder recuperar el valor almacenado en suEdad, como dijimos antes todo aquello en lo privado no sera accedido por el programa, para ello debemos tener metodos en la parte publica, estos son llamados accesos indirectos y si bien el programa no puede acceder a la parte privada, el metodo si porque esta dentro de la misma clase. Sigamos con el siguiente metodo:

void Gato::AsignarEdad(int edad)
{
suEdad = edad;
}
Anuncios

Este metodo es similar al anterior pero lo utilizaremos para asignarle un nuevo valor a suEdad por medio del valor enviado al metodo, en este caso llamado edad, sigamos con el ultimo metodo:

void Gato::Maullar()
{
cout << "Miau!\n";
}
Anuncios

Este ultimo metodo se encarga de mostrar un mensaje de pantalla, en este caso es Miau!, como pueden ver este es un metodo simple de los que se pueden usar en clases donde no necesariamente tiene que conceder accesos a la parte privada sino simplemente es una notificacion, con los tres metodos explicados prosigamos con el main(), nuestra primera linea sera para crear el objeto en base a la clase:

Gato Pelusa;
Anuncios

Como pueden ver primero va el nombre de la clase en forma EXACTA a cuando lo declaramos, despues tendremos las siguientes dos lineas:

Pelusa.AsignarEdad(5);     
Pelusa.Maullar();
Anuncios

Como pueden ver no utilizamos la clase sino al objeto creado por nosotros y desde alli accederemos a los metodos publicos de nuestra clase, el primero sera el encargado de asignar el valor 5 a la variable suEdad que esta en la parte privada de la clase, luego mostraremos el mensaje de Miau! en la pantalla, nuestras siguientes lineas se encargaran de mostrar un mensaje en pantalla, el cual es la edad de nuestro gato y para ello utiliza el otro metodo, ObtenerEdad(), y finalmente mostramos otro maullido al final, si lo compilamos y ejecutamos obtendremos esta salida:

tinchicus@dbn001vrt:~/programacion/c++$ ./program/clase00
Miau!
Pelusa es un gato que tiene 5 años de edad.
Miau!
tinchicus@dbn001vrt:~/programacion/c++$
Anuncios

En este primer ejemplo podemos ver como llamamos a un metodo dentro de la clase para mostrar un mensaje, Maullar(), hemos modificado el valor de una variable dentro de la parte privada, AsignarEdad(), y por ultimo hemos obtenido esa informacion modificada, ObtenerEdad(), ahora pasemos a otra parte interesante de las clases, es que al igual que las variables se puede iniciarlas con un valor X, este metodo se llama constructor y por cada constructor existe un destructor. Esto no son obligatorios dado que el compilador genera unos predeterminados cuando no son declarados, como en el caso anterior pero en el caso de que se declaren el destructor se lo asigna con un tilde (~). Como vimos en el ejemplo anterior la declaracion predeterminada del constructor seria esta linea:

Gato Pelusa; 
Anuncios

Ahora para entender un poco mejor el concepto de constructor y destructor veamoslo en el siguiente ejemplo, que es basicamente el anterior pero modificado para estas 2 declaraciones nuevas:

clase01.cpp

# include <iostream>

using namespace std;

class Gato
{
public:
        Gato (int edadInicial);
        ~Gato();
        int ObtenerEdad();
        void AsignarEdad(int edad);
        void Maullar();

private:
        int suEdad;
};

Gato::Gato(int edadInicial)
{
        cout << "Ingresando al constructor...\n";
        suEdad=edadInicial;
}

Gato::~Gato()
{
        cout << "Ingresando al destructor...\n";
}

int Gato::ObtenerEdad()
{
        return suEdad;
}

void Gato::AsignarEdad(int edad)
{
        suEdad = edad;
}

void Gato::Maullar()
{
        cout << "Miau!\n";
}

int main()
{
        Gato Pelusa(5);
        Pelusa.Maullar();
        cout << "Pelusa es un gato que tiene ";
        cout << Pelusa.ObtenerEdad() << " años de edad.\n";
        Pelusa.Maullar();
        Pelusa.AsignarEdad(7);
        cout << " Ahora Pelusa tiene ";
        cout << Pelusa.ObtenerEdad() << " años de edad.\n";
        return 0;
}
Anuncios

El programa es exactamente el mismo pero ahora agregamos estas dos lineas en la clase, en su seccion publica:

Gato (int edadInicial);     
~Gato();
Anuncios

Como pueden ver tambien son dos prototipos de constructor, primera linea, y del destructor, segunda linea, ahora vamos a ver la definicion de cada uno de ellos, comencemos por el constructor:

Gato::Gato(int edadInicial)
{
cout << "Ingresando al constructor…\n";
suEdad=edadInicial;
}
Anuncios

A diferencia de las funciones estan no llevan un tipo de variable porque son propiamente de la clase, por este motivo va primero el nombre de la clase, los dos puntos (::) para unirlo con el constructor, el nombre del constructor que corresponde porque como existen las sobrecargas de funciones tambien existen las sobrecargas de constructores, las cuales veremos mas adelante, y por este motivo deben coincidir con el constructor a definir, hoy como tenemos un solo constructor no es tan dificil, despues dentro del bloque mostraremos un mensaje de aviso cuando ingresamos al mismo, no es obligatorio pero en este caso lo hacemos por un tema ilustrativo, y luego lo que si hacemos es asignarle a suEdad el valor enviado al constructor iniciando a la variable con el valor informado cuando creamos el objeto, pasemos al destructor:

Gato::~Gato()
{
cout << "Ingresando al destructor…\n";
}
Anuncios

En este caso, el destructor es el encargado de liberar la memoria cuando el programa es finalizado, es decir el programa, las variables y todo aquello que haya generado el programa, esto en general lo hace automaticamente y no necesita una intervencion nuestra, por lo general ira vacio salvo raras excepciones donde especificaremos algo en particular, en nuestro caso le pusimos un mensaje para que nos notifique cuando es llamado pero esto no es obligatorio, ahora pasemos a main() para ver las nuevas lineas, pasemos a ver la primera:

Gato Pelusa(5);
Anuncios

Como pueden ver a diferencia del ejemplo anterior, como tenemos un constructor que puede recibir informacion cuando creamos el objeto, le informamos la edad a asignar a nuestro gato, en este caso 5, luego llamaremos a Maullar(), luego mostraremos la edad por medio de ObtenerEdad(), llamaramos a Maullar() despues utilizaremos AsignarEdad() para asignarle un nuevo valor a suEdad, en este caso 7, luego volvemos a mostrarlo otra vez por medio de ObtenerEdad() y por ultimo utilizamos un Maullar() nuevamente si lo compilamos y ejecutamos:

tinchicus@dbn001vrt:~/programacion/c++$ ./program/clase01
Ingresando al constructor…
Miau!
Pelusa es un gato que tiene 5 años de edad.
Miau!
Ahora Pelusa tiene 7 años de edad.
Ingresando al destructor…
tinchicus@dbn001vrt:~/programacion/c++$
Anuncios

Observen como se modifico suEdad gracias al constructor y al valor enviado y luego por medio de AsignarEdad() volvimos a modificarlo, tambien tenemos como lo primero que llamamos fue el constructor, se ve en la primera notificacion, y como al final podemos ver como se invoco automaticamente al destructor, este es llamado automaticamente cuando finaliza el programa por eso no fue necesario invocarlo.

Nota: Recuerden que si no se declara un constructor y destructor el programa los genera automaticamente y siempre por cada constructor hay un destructor pero despues veremos que en la practica no es tan asi.
Anuncios

En las clases debemos utilizar el miembro const, esto se implementa en el caso de los metodos que no deben variar su valor, en el ejemplo anterior se podria haber declarado el prototipo de ObtenerEdad() de la siguiente forma:

int ObtenerEdad() const;
Anuncios

Dado que el metodo lo unico que hace es recuperar la informacion almacenada en suEdad y mostrar atraves de cout el valor de suEdad. Para declarar el metodo tambien cambia, se debe hacer de la siguiente forma:

int Gato::ObtenerEdad() const
{
return suEdad;
}
Anuncios

Si realizamos este cambio el metodo ObtenerEdad() no puede modificar su resultado pero esto no implica que no se puede modificar suEdad atraves del otro metodo que es AsignarEdad(). Esto es bueno para evitar cometer errores en el resto del programa cuando sabemos que ese metodo solo debe tener un formato de salida y no debe ser modificado por nada ni nadie, por ejemplo si hicieramos la siguiente modificacion:

int Gato::ObtenerEdad() const
{
return suEdad++;
}
Anuncios

Cuando lo compilemos, el mismo compilador nos dara un error diciendo que el metodo declarado es de solo lectura (read-only) por este motivo no se compilara. Esto se debe a lo que dijimos anteriormente que una vez que se declara const a un metodo, este ya no puede modificar su salida. Otro caso del ejemplo anterior es Maullar(), tambien deberia ser declarado como const. Una buena practica para las clases y metodos es declararla por medio de un archivo externo (tambien conocido como archivo de encabezado) a nuestro programa y luego ser invocado atraves de #include, la extension de este archivo deberia ser .h, .hp o hpp. Esto va a depender de que tipo de extension utilice el compilador que esten utilizando, en el caso mio acepto la extension .h, esto es una buena practica para evitar que nuestro archivo principal quede demasiado complejo para poder verificar en caso de algun error. Ahora veamos un ejemplo de implementacion inline, como hemos visto anteriormente a la funcion inline en el caso de implementacion de metodos seria algo asi:

inline int Gato::ObtenerEdad() const
{
return suEdad;
}
Anuncios

Tambien podemos definir directamente nuestros metodos en un clase, esto se puede aplicar a nuestro casos anteriores y al archivo de encabezado, es decir en lugar de declarar un prototipo y luego definir, podemos hacer como se ve a continuacion:

int ObtenerEdad() { return suEdad; }
Anuncios

Como podemos ver en lugar de definirlo externamente, cuando creamos el prototipo agregamos el bloque entre las llaves y las instrucciones dentro del mismo. Para que quede un poco mejor explicado veamos un ejemplo donde primero crearemos un archivo de encabezado con la declaracion de la clase y luego el programa donde se incluye la misma, el nombre del archivo debe ser como se ve a continuacion:

gato.h

# include <iostream>

using namespace std;

class Gato
{
public:
        Gato (int edadInicial);
        ~Gato();
        int ObtenerEdad() { return suEdad; }
        void AsignarEdad(int edad) { suEdad=edad; }
        void Maullar() const{ cout << "Miauuuuu!!!\n"; }
private:
        int suEdad;
};

Gato::Gato(int edadInicial)
{
        cout << "Ingresando al constructor\n";
        suEdad=edadInicial;
}

Gato::~Gato()
{
        cout << "Ingresando al destructor\n";
}
Anuncios

Como pueden ver en este archivo, transferimos toda nuestras clase, definimos nuestro constructor y destructor todo en el archivo de encabezado, ahora si procedamos al archivo con el programa en si, no debemos llamarlo estrictamente como lo nombre yo pero si deben respetar el nombre del archivo anterior porque es el cual va a ser incluido:

clase_ext.cpp

# include <iostream>
# include "gato.h"

using namespace std;

int main()
{
        Gato Pelusa(5);
        Pelusa.Maullar();
        cout << "Pelusa es un gato que tiene ";
        cout << Pelusa.ObtenerEdad() << " años de edad.\n";
        Pelusa.Maullar();
        Pelusa.AsignarEdad(7);
        cout << " Ahora Pelusa tiene ";
        cout << Pelusa.ObtenerEdad() << " años de edad.\n";
        return 0;
}
Anuncios

Como pueden ver la unica diferencia con respecto a todo lo visto anteriormente es que incluimos el archivo gato.h y no tenemos a nuestra clase, antes de compilarlo deben recordar dos cosas:

  1. La libreria debe estar en el mismo directorio que el codigo para compilarlo
  2. En caso contrario, deben ponerlo en algun path para que el compilador puede encontrarlo e incluirlo

Con esto en cuenta pueden proceder a compilarlo y ejecutarlo:

tinchicus@dbn001vrt:~/programacion/c++$ ./program/clase_ext
Ingresando al constructor
Miauuuuu!!!
Pelusa es un gato que tiene 5 años de edad.
Miauuuuu!!!
Ahora Pelusa tiene 7 años de edad.
Ingresando al destructor
tinchicus@dbn001vrt:~/programacion/c++$
Anuncios

Esta es una practica muy habitual entre los desarrolladores porque nos da la posibilidad de poder crear archivos donde almacenamos las clases y luego por medio de include las incluimos en nuestro programa, esto solamente no nos facilita la depuracion sino nos deja mejor esteticamente el programa.

Anuncios

En resumen, hoy hemos visto que son las clases y objetos, como se definen, como se declaran, como se trabaja con ellos, que son los constructores y destructores, otras formas de implementar nuestras clases, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00