En esta nueva entrega de programación en C++ nos dedicaremos a aprender a crear clases en C++ usando estructuras estáticas o dinámicas. La diferencia entre ambas es que en una puedes tener el control total sobre la memoria y por lo tanto vaciarla en el momento justo, en este caso hablamos de estructura de datos dinámicos o struct, más adelante hablaremos de ello. Hoy toca hablar de las estructuras básicas, que son las estáticas. En una clase podemos usar otras bibliotecas como la clase vector, string, etc. En esta serie de tutoriales veremos que no usaremos en ningún momento clases externas. Trabajaremos sobre arrays (no vectores de la clase vector). Explicaré también que son los nodos en memoria dinámica, etc. La idea es que tengáis que pensar sobre el ejercicio, que hay que hacer para que funcione, que metodos privados necesitas para esta clase, etc. Cualquier duda será respondida por mi o quien sepa la respuesta, la mejor manera de de aprender es de los fallos. Una vez dicho esto empecemos con las estructuras estáticas.
La programación orientada a objetos o POO es un paradigma de programación que usa los objetos en sus interacciones, para diseñar aplicaciones y programas informáticos. Está basado en varias técnicas, incluyendo herencia, cohesión, abstracción, polimorfismo, acoplamiento y encapsulamiento. Su uso se popularizó a principios de la década de los años 1990. En la actualidad, existe variedad de lenguajes de programación que soportan la orientación a objetos.
Los objetos son entidades que tienen un determinado estado, comportamiento e identidad:
Un objeto contiene toda la información que permite definirlo e identificarlo frente a otros objetos pertenecientes a otras clases e incluso frente a objetos de una misma clase, al poder tener valores bien diferenciados en sus atributos. A su vez, los objetos disponen de mecanismos de interacción llamados métodos, que favorecen la comunicación entre ellos. Esta comunicación favorece a su vez el cambio de estado en los propios objetos. Esta característica lleva a tratarlos como unidades indivisibles, en las que no se separa el estado y el comportamiento.
Ejemplo de objeto: Tipoclase a(valor) → casa a
En este caso creamos un objeto con identificador (el nombre de la clase) “casa”.
La declarión de la clase con todos los metodos privados y publicos estarán contenidos en el fichero fuente “.hpp”:
casa.hpp
casa.cpp
La implementación de dicha clase estará contenida es un fichero aparte con formato “.cpp”:
Una vez que el encabezado está incluido, se comprueba si un valor único (en este caso _CASA_H) se define. Entonces, si no está definida, se define y continúa el resto de la página. Cuando el código se incluye de nuevo, la primera ifndef falla, lo que resulta en un archivo en blanco. Esa declaración tiene como función evitar doble de los identificadores tales como tipos, enumeraciones y las variables estáticas.
Ejemplo:
#ifndef _CASA_HPP_ //Si no está definida #define _CASA_HPP_//Definela #include <iostream> using namespace std;
Esto pertenece al fichero casa.hpp, si en nuestra clase hacemos uso de string habrá que incluirla como la clase vector, en este caso tan sólo tenemos la clase iostream.
Cuando creamos una clase tenemos que pensar que métodos publicos (cualquiera puede tener acceso a dichas funciones) y que métodos privados (solamente está visible para quien programa dicha clase). Veamos un ejemplo y lo analizamos:
class casa { public: casa() //Metodo para crear la casa int miembros(); //Retorna el numero de miembros void inserta_miembro (char a); //Inserta un miembro a la casa char donde_viven (casa& a); //Retorna la dirección de la casa int numero(casa& a); //Retorna el numero de la casa void miembros (casa& a); //Muestra los miembros void Imprimir(ostream& os); //Imprime la casa static const int MAX = 20; //Variable global private: int familia; //Contador del numero de miembros char miembros[MAX]; //Contendrá como mucho 20 miembros por casa }
Cuando hagamos las implementaciones usaremos el prefijo "nombre_de_la_clase::nombre funcion()", ejemplo:
#include "casa.hpp" casa::casa(){ familia=0; //no hay nadie de momento en esa casa } //La constructora por defecto crea el objeto iniciando sus privados a 0.
Una vez leido estas breves entradas pero suficientes para realizar el ejercicio, quiero que hagais los siguientes ejercicios:
Comentarios
Buenas
Hola Recoco.
No sabía que te habías puesto a hacer tutoriales. Si quieres te puedo echar una mano, criticándote un poco, para que me odies ;)
Te diría por ejemplo, que el constructor no crea el objeto, lo inicializa. El objeto se crea con "new" (si está en memoria dinámica, o solo declarándolo, si está en el stack). Una vez que ya está creado el edificio es cuando se llama al constructor para que "pinte las paredes y amueble el interior". Estoy seguro de que tú ya lo sabías, pero el que lo lea no.
También, aunque parece obvio, deja bien claro que el #ifndef de la cabecera hay que cerrarlo al final del .hpp con un #endif. No importa cuantos años lleves programando, de vez en cuando caes en este tipo de cosas y te da algún dolor de cabeza. Por cierto, la cabecera puede ser .hpp, pero también puede ser .h (o incluso .hxx, o sin extensión, como <iostream> por ejemplo). De hecho, según mi experiencia, hay más gente que use .h que .hpp en C++, aunque personalmente prefiero usar hpp cuando es C++ y .h para C. En fin, solo te lo comento porque parece que obligatoriamente tengas que usar .hpp, que no es así.
No dejes de hablar del estilo, que es bastante importante. Por ejemplo, por consenso, las clases (y estructuras), aunque las puedes llamar como te de la gana y el compilador no se queja, se suelen usar nombres que empiecen por mayúsculas, mientras que los métodos, objetos, etc se llaman con minúsculas. De esta manera declararías tu casa como:
Casa a;
(o inclusoCasa casa;
). Así no hay equívocos: si ves casa es el objeto y si ves Casa es la clase. Es verdad que en libstd C++ las clases no suelen estar en mayúsculas (como iostream o string), pero creo que es debido porque sigue las nomenclatura de C. Lo cierto es que en POO (Java, Objective-C y un largo etcétera) es casi estandar lo de usar mayúsculas para las clases, por lo que el 99% de los programadores de C++ también lo hacen así.También vendría bien que diferencies la declaración de la definición (implementación) de un metodo. Más o menos ya lo haces, llamándolo implementación, pero es útil saber qué es la definición de un método. No es que quiera ser tiquismiquis, es que el compilador g++ te da errores del tipo (error en la declaración tal o en la definición cual), y si no sabes diferenciarlo es un poco lioso.
Si usas el paso por referencia para no copiar el objeto, acuérdate de poner el const, a no ser que sea un parámetro de entrada y salida. Por ejemplo
void fn (const Casa &a);
. Luego, para usar el objeto a solo podrías llamar a métodos declarados const (int fn (int x) const;
). Esto mejor no lo expliques en un tutorial tan inicial, que vas a liar a más de uno. Te lo digo solo para que lo sepas ;)Por ultimo, además del public y el private tienes el protected, que es muy importante, ya que es como el private (otras clases externas no pueden acceder), pero sí que permite acceder a clases hijas. Lo dicho, probablemente lo sabías, pero te lo recuerdo ;). Cuando empieces con la herencia te vendrá bien haberlo dejado claro.
Por lo demás está genial. Sigue así máquina!
Saludos
Dennis Ritchie. Padre de C y cocreador de UNIX.
R.I.P.