Por favor, no copiéis este tutorial sin autorización mía. ¡Gracias!ATENCIÓN: Este tutorial, al igual que su autor, es propenso a tener errores. ¡Avisadme y los corrijo, hamijos!Éste tutorial intenta ser una continuación del tutorial iniciado por blipi en el hilo
hilo_tutorial-programando-en-c_1546639. Recomiendo su lectura y comprensión ya que es necesario una serie de conocimientos para poder seguir éste tutorial. Espero que éste tutorial sea una buena referencia para que os animéis a aprender. Un saludo a todos.
Capítulo 1: Y... ¿qué es eso de la programación orientada a objetos?C es un lenguaje diseñado en el año 1972 por Ritchie (blah, blah, blah). Poco a poco la programación aumentaba su complejidad, y para ello se creó la Programación Orientada a Objetos (a partir de ahora
OOP). No quiero aburriros como empiezan todos los libros hablando de conceptos como
herencia o
encapsulación, porque soy consciente de que no serviría de nada hablar de cosas que no se conocen (¿¡Por qué todos los libros se empeñan en hacerlo!?). Vamos a explicar la OOP en la vida real:
Términos que necesitamos conocer (Introducción Gráfica):1. El objeto: Aquí tenemos dos objetos. La
frutería Pepe, y
mi coche (o el coche de
@Adelaiglesia). Éstos son dos
objetos que utilizo en mi vida diaria. Cada objeto tiene su identidad. ¡Nadie confundiría mi Coche con la frutería Pepe!.
2. La clase:El objeto
mi coche pertenece a la
clase coche. El
coche de Bill Gates, aunque cuesta mucho más que el mío, también pertenece a la
clase coche.
3. Los atributos:Como hemos visto arriba, a pesar de que mi coche y el de Bill Gates pertenecen a la clase coche, el suyo es MUUUUCHO más caro. ¿Y por qué? El secreto está en sus
atributos. Mirad:
Velocidad máxima:Mi coche: 115 en sus mejores tiempos
El coche de Bill Gates: 330 y subiendo
Pintura:Mi coche: Verde descuartizado
El coche de Bill Gates: Negro metalizado
Aceleración:Mi coche: 3 km/h a los 100 segundos
El coche de Bill Gates: 3 segundos a los 100 km/h
Equipamiento:Mi coche: Rueda de repuesto
El coche de Bill Gates: Ordenador de a bordo, GPS, televisión FULL HD, Asientos calefactados, circulito para el vaso...
Caja:Mi coche: Caja flamenca, por el ruido que hace al meter la marcha
El coche de Bill Gates: 6 velocidades automáticas con relación de marcha personalizable
4. Los métodos (o mensajes):Aunque
el coche de Bill Gates sea mucho mejor que el mío, podemos manejarlo mediante los mismos métodos. Éstos métodos son el método
acelerar,
frenar,
girarDerecha,
girarIzquierda... ¡Si un día me toca el
euromillón y me compro un coche como el de Bill Gates sabré manejarlo porque
es de la misma clase que mi coche! A esto se le conoce cómo
abstracción. Ésto significa que a nosotros como usuarios de la clase (
del coche) no nos importa lo más minimo como demonios hace el coche para acelerar, si no que lo que queremos es que al apretar el acelerador el vehículo avance, y eso sirve para cualquier coche. Ésta es una de las principales ventajas de la Programación Orientada a Objetos.
Otro punto importante es que
los métodos son únicos de su clase. Es decir, cualquier objeto
coche comprenderá el
metodo acelera. Pero si intentamos que la
Frutería Pepe realize el
metodo acelera, nos encontraremos con que el objeto
frutería no comprende ése metodo:
A la frutería Pepe podremos enviarle otros
mensajes (métodos), que serán
damePeras(5), dameManzanas(8), tePago... Como también ocurre con la
clase coche a nosotros no nos importa como han llegado las peras a la frutería Pepe. ¡De eso ya se encarga la clase frutería! Cuando vamos a la frutería Pepe a por manzanas ¡Nunca se nos ha ocurrido pensar como han llegado hasta allí! Esa es la base de la programación orientada a objetos. Aunque nos podemos hacer una idea:
¡Esto tiene ventajas! Si algún día Pepe encuentra unas manzanas mas ricas en un sitio diferente (
fruteria Pepe ha mejorado su codigo), ¡Nosotros podremos pedirle manzanas igualmente, aunque las obtenga de otra manera o de otro sitio! Así aunque el
procedimiento de obtener manzanas cambie, el mensaje seguirá siendo el mismo, Pepe lo entenedrá y nos dará Manzanas. ¡Además nos damos cuenta de que Pepe ha utilizado la
clase coche para ir a recojer las manzanas, concretamente el objeto
el coche de Pepe, y sus metodos
acelerar, frenar, girarIzquierda, ...
Actividades propuestas:1. Piensa en tu coche y en el coche de algún vecino o familiar. ¿Qué atributos los diferencian?2. ¿Qué métodos podría tener una Televisión? ¿Y qué atributos diferencian tu TV de otras?Anexo I: C++ y sus diferencias con CYa es hora de dejarnos de tantas
fruterías y coches y ponernos manos a la obra. Observemos los siguientes códigos:
#include <stdio.h> vs
#include <iostream>: Son las bibliotecas de C y de C++ de flujo de entrada y salida, es decir, las que se comunican con el sistema operativo para recojer datos del teclado y mostrarlos por la pantalla. La diferencia es que
<stdio.h> no está orientada a objetos y
<iostream> si, así que la utilizaremos a partir de ahora. ¿Que por qué? En mi tierra hay un refrán que dice
"Donde fueres, haz lo que vieres" así que si estás aprendiendo a programar en C++ utiliza <iostream>.
printf("Hola Mundo"); vs
std::cout << "Hola mundo" << endl; : El primero es una
función de C en stdio.h y el segundo es un metodo de la clase std que utiliza el operador de inserción de flujo. Lo utilizaremos habitualmente, así que observaremos algunos ejemplos:
Mostrar una cadena:std::cout << "Cadena de texto aqui" << endl;
Muestra: Cadena de texto aqui
Mostrar una variable:int a = 5;
std::cout << a << endl;
Muestra: 5Mostrar una cadena con una variable (o varias):int a = 5, b = 7;
std::cout << "A vale " << a << " y b vale << b << endl;
Muestra: A vale 5 y b vale 7Así vemos que podemos encadenar todo lo que queramos mediante el operador de
inserción de flujo, y cuando pongamos endl saltará de línea, aunque podemos seguir utilizando dentro de las cadenas "\n" y demás modificadores.
Igual que existe el
operador de inserción de flujo (<<) existe el
operador de extracción de flujo (>>) que es el equivalente a scanf("%d", &num); . Así:
scanf("%d", &num); se escribe
std::cin >> num; Vemos:
Leer un numero de cualquier tipo:int a;
std::cin >> a ;
Si introducimos 5, a = 5.float a;
std::cin >> a ;
Si introducimos 5, a = 5.0, por ser de coma flotante simple.Leer una cadena:Utilizaremos la biblioteca
string:
#include <iostream>
#include <string>
(...)
std::string a;
std::cin >> a ;
Si introducimos "Esto es una cadena", a = "Eso es una cadena".getchar() vs
std::cin.get(): Volvemos a lo mismo, getchar es una
función de C y
get es un
método de la clase
cin, que a su vez pertenece al
namespace std. No os preocupéis si no cogéis bien los términos, más adelante iremos profundizando en cada uno y no quedará ninguna duda.
Actividades propuestas:1. Haz un programa que lea dos números del teclado con la biblioteca <iostream> y que los muestre por pantalla sumados.2. Haz un programa que lea una cadena del teclado y la muestre por pantalla.Using namespace std:Como habréis podido obserbar delante de cin y cout ponemos continuamente std::. Nos estamos refiriendo a
donde esta cin y cout. Como observamos es muy repetitivo. Si colocamos debajo de las instrucciones del preprocesador
using namespace std; le estaremos diciendo al
linker que apartir de ahora todo lo que no encuentre o no sepa donde está lo busque dentro del
namespace std. Vamos que lo ponemos para ahorrarnos escribir std:: a cada rato. Obserbad:
Capítulo 2: La claseA partir de aquí el vocabulario que utilizaremos será más relacionado con la programación orientada a objetos. Empecemos definiendo como se programa una clase:
class nombredelaclase {
public:atributos ó metodos publicos;private:atributos ó metodos privados;};Veamos nuestra primera clase de ejemplo: La clase
fracción, que representará una fracción matemática. ¿Qué
atributos tiene una fracción matemática? Pues un
denominador y un
numerador. Más adelante veremos los métodos que pueda tener:
¿Y por que lo metemos en
private? Por el concepto de
encapsulación. No queremos que nadie desde fuera pueda tocar nuestro numerador o nuestro denominador sin nuestro permiso. ¡Imaginate que alguien mete un 0 en el denominador! ¡Produciría un error a la hora de dividir y se nos iria todo al
carajo! Como observaréis he metido la clase fracción dentro de un archivo llamado fracción.h, que irá separado de nuestro main. Vamos a crear el main para que tengamos un programa que se pueda ejecutar:
Al ejecutar la consola muestra una bonita apariencia negra. Si observáis hemos creado un objeto de la clase fracción, concretamente el objeto
unafraccion. Vamos a hacer algunos métodos para empezar a interactuar con la clase:
Observemos lo que hemos hecho: Dentor de la definición de la clase escribiremos el
prototipo del método, y fuera de la misma escribiremos la
implementación. Si os fijáis, la implementación lleva delante del nombre del método el nombre de la clase seguida de :: (operador de ámbito). Pues bien, esto es lo que le indica al compilador que el
metodo corresponde a esa clase. Así escribiremos tipo
clasealaquepertenece::metodo(argumento1, ...) {
En el main solamente hemos hecho un par de cout con las llamadas a los metodos que acabamos de crear, para como nos devuelven los valores de la fracción.
Veamos que ocurre al compilar y ejecutar: Nota: Según el compilador pueden aparecer valores totalmente aleatorios ó 0. En el caso de g++ que es el que yo utilizo, aparece 0. Veremos ahora qué hacer para que nuestros objetos se inicialicen con lo que nosotros queramos:
El constructorEl constructor es un método que sirve para inicializar los
atributos de una clase al valor que se quiera cuando ésta es creada. Los constructores son un tanto especiales, por varios motivos:
- Tienen el mismo nombre que la clase a la que pertenecen
- No retornan ningún valor
- Deben ser públicos siempre. No tiene sentido un constructor privado
Y ahora os preguntaréis, ¿Y por qué hacer un constructor?. Para mantener nuestra clase
consistente. Cuando se programa una clase es importante que desde su creación hasta su destrucción sea consistente, es decir, que no ocasione errores ni estados no posibles. Nuestra clase
fracción es inconsistente en éste momento porque tiene un denominador 0, y si construimos un método que devuelva la división de los dos
atributos, provocará un error. Con el constructor inicializaremos nuestra clase a 1 de la siguiente manera:
Observemos las peculiaridades antes comentadas. No devuelve ningún tipo de datos (ni int, ni void ni ná), no recoge parámetros (tiene los paréntesis en blanco) y tiene el mismo nombre que la clase. Ahora la ejecución muestra 1 y 1, tal y como declara el constructor:
Así pues cada vez que creemos un objeto de la clase fracción sus
atributos.