Sie sind auf Seite 1von 49

http://macedoniamagazine.frodrig.com/poo1.

htm

Curso de Programacin Orientada a Objetos en C++


Artculo realizado por Fernando Rodrguez.

Captulo 1. Introduccin al curso de POO Bienvenidos a otro curso ms de Macedonia. Esta vez le ha tocado el turno a la tan traida y llevada POO, o lo que es lo mismo, a la Programacin Orientada a Objetos. El por qu de este curso se debe a varias razones. La primera de todas a que siempre haba tenido en mente realizar para mi un breve librito en donde explicar de una manera rpida los conceptos de la POO y tener as una referencia rpida un tanto personal. Sin embargo, ahora que estamos embarcados en Macedonia, haba pensado realizarlo especialmente para la revista y con un caracter mucho ms abierto, para que sirviera a los no iniciados tambin. Antes de pasaros a mostrar los captulos que he diseado para el curso, os voy avisar que, tal y como reza el ttulo del curso, se utilizar el lenguaje C++ para mostrar todos los ejemplos. El por qu es bien sencillo, el C++ es el lenguaje ms extendido hoy en da para la realizacin de programas orientados a objetos de temtica general. Pese a que el C++ no es un lenguaje orientado a objetos puro, s que incluye caractersticas muy poderosas del mismo y que nos sern de gran ayuda a la hora de realizar nuestros programas. Por supuesto, no voy a hacer una enseanza del C, es decir, para seguir este curso has de saber programar en C tradicional, ya que, como veris el C++ viene a ser un superconjunto del C, lo nico que cambia es la metodologa que utilizaremos, esto es, la POO frente a la metodologa estructurada y alguna que otra novedad que incluye el C++ frente al C para poder llevar a buen puerto la ya citada metodologa orientada a objetos. Creo que hasta aqu he dejado ms o menos claro cuales van a ser las exijencias del curso, ahora os voy a plasmar un pequeo boceto de los captulos que tengo en mente hacer, ah van: Fundamentos de la POO. Novedades del C++ frente al C. La piedra angular del C++; las clases Aprovechmonos de la POO; la jerarqua de clases y la herencia. Hagamos cdigo ms inteligente; polimorfismo y funciones virtuales. Utilizando la sobrecarga. La utilidad de las variables y funciones estticas. Las funciones amigas. Las ventajas de new y delete.

Me supongo que los captulos que ahora os muestro sufrirn modificaciones, al menos, en el ttulo del mismo, ya sabeis todo se puede mejorar ;).

1 de 2

30/01/2012 10:57 a.m.

http://macedoniamagazine.frodrig.com/poo1.htm

[Aula Macedonia] [Curso de POO en C++]

AULA MACEDONIA a MACEDONIA Magazine

2 de 2

30/01/2012 10:57 a.m.

http://macedoniamagazine.frodrig.com/poo2.htm

Curso de Programacin Orientada a Objetos en C++


Artculo realizado por Fernando Rodrguez.

Captulo 2. Fundamentos de la POO Por qu la POO? Seguro que muchos de vosotros os habreis preguntado unas cuantas veces qu es eso de la programacin orientada a objetos, por qu todo el mundo no hace ms que hablar de ella como la salvacin de la ingeniera del software moderno, etc. Bien, la POO supone, bajo mi punto de vista, el nico camino posible a seguir para la realizacin de programas en la actualidad. Para poder llegar a tal conclusin tan slo debes de fijaros en los requisitos que exije la realizacin de un proyecto de software en la actualidad. Por un lado estn las ingentes cantidades de informacin a tratar en todos ellos, por otro lado, el equipo de personas que intervienen es bastante numeroso y todos deben de poder utilizar el cdigo que, el resto de miembros del equipo, han realizado sin tener que complicarse la vida. En tercer lugar, los programas actuales ocupan miles de lneas, con lo que no se puede programar a la ligera, hay que seguir unas reglas muy estrictas, que nos permitan construir programas robustos en cuanto al uso de sus estructuras de datos. Otro de los aspectos que hay que tener en cuenta es el de reutilizacin, cualquier programa ha de estar lo suficientemente bien diseado para que las partes bsicas del mismo puedan servir en la realizacin y construccin de otros, ya que no nos podemos permitir el "lujo" de estar perdiendo tiempo construyendo una y otra vez las mismas cosas. Hay que aprovecharse de cdigo que ya est hecho. Hasta aqu os he citado algunas de las caractersticas que exijen los proyectos de software de la actualidad. Negar alguna de ellas no es ms que engaarse. Atrs quedaron los felices das en los que un programador poda abarcar un proyecto de software. El ejemplo ms claro lo tenes en el campo de la programacin de juegos. Antes bastaba con un programador, un grafista y ocasionalmente un msico para producir un sensacional juego, sin embargo, ahora para realizar un juego son necesario varios programadores que han de estar colaborando contnuamente, amn del resto de artistas que han de participar en la creacin de la obra. Es por ello que no se puede acudir a la programacin tradicional para la construccin de programas en la actualidad, ya que esta, no se diseo para dar soporte a grandes desarrollos de software con continuas actualizaciones y con multitud de equipos de desarrollo destinados a un campo especfico del proyecto.

Y...por dnde van los tiros? Vereis, la POO se basa en utilizar estructuras de datos en las que, tanto las variables como las funciones que manipulan dichas variables se encuentran unidas. Tan slo teneis que imaginaros la defincin de una estructura en C (struct). Todos sabis que en las estructuras slo es posible meter distintos campos que no son ms que variables. As podis construir una estructura que tenga un campo de tipo entero (int) otro que sea de tipo caracter (char), arrays de un determinado tipo de dato, etc. Por otro lado, estn las funciones que tratan a dichas estructuras de datos. En todo momento son "externas", esto es, cualquier funcion PUEDE (si cumple unas caractersticas obvias) acceder a un campo de una estructura y trabajar con l. Pues bien, ahora imaginaros que teneis una estructura en la que estn metidos no slo los campos de variables de toda

1 de 3

30/01/2012 10:58 a.m.

http://macedoniamagazine.frodrig.com/poo2.htm

la vida, sino que, adems, estn metidas, tambin, las funciones para manipularlas, de tal modo que, slo esas funciones que se encuentran metidas en la estructura, pueden manipular esas variables que, tambin, se encuentran en la estructura. Ya os lo habes imaginado?, si habeis podido pillar la idea, sabed que para poder crear una variable de dichas estructuras debereis de crear un OBJETO a dicha estructura, s!, los objetos no son ms que variables o, mejor dicho, INSTANCIAS, a las estructuras, que a partir de ahora llamaremos CLASES, que poseen tanto variables como funciones para manipular dichas variables. Bueno, si habeis logrado quedaros con que son los OBJETOS, INSTANCIAS y CLASES, teneis premio, ya que habeis logrado entender lo suficiente como para poder seguir con xito. Si no has logrado pillar la idea de todo lo puesto ms arriba, no te preocupes, se te irn aclarando a lo largo de los captulos, pero te recomiendo que te vuelvas a leer lo de antes.

Los pilares de la POO Despus de presentaros una idea general de lo que supone la POO frente a la programacin estructurada de toda la vida, os voy a comentar los pilares en los que descansa, esto es, las caractersticas que la hacen tan potente. Como veres al acabar de leer este captulo, la POO posee una serie de caractersticas estupendas para poder trabajar en equipo un proyecto de software, adems de permitirnos construir programas envidiablemente robustos.

Encapsulacin de datos. La encapsulacin de datos, no es ms que la idea que expuesta ms arriba, esto es, la idea de mezclar las variables y las fuciones que sirven para manipular dichas variables, en una misma estructura de datos. Por ahora y hasta que no veamos las clases, quedaros con que todo esto se podra lograr, metiendo en una struct tradicional de C un campo destinado a las variables y otro a las funciones. Lgicamente, la posiblidad de meter funciones en la struct se la debemos al C++. La encapsulacin de datos, es fundamental en la POO, ya que nos permite construir objetos que, como ya se cit ms arriba, no son ms que instancias (o variables hablando mal) a dichas struct. Las ventajas que reporta la encapsulacin de datos son estupendas, ya que nos permiten crear variables totalmente protegidas de posibles efectos no deseados, como cambio de valor por descuido o efectos laterales gracias a tener unas fuciones que se encargan de realizar todas las operaciones sobre ellas, es decir, no penseis que si os construis un objeto con sus propias variables vais a dar vosotros el valor a la variable directamente como se ha hecho toda la vida (que tambin se puede hacer). Lo que hareis ser llamar a una funcin que lo nico que que haris ser realizar dicha asignacin. Seguro que ahora mismo estais pensando que hacer eso es una estupidez, para qu construir una funcin que haga, por ejemplo, a=b cuando yo mismo lo puedo hacer directamente?, la respuesta es bien sencilla, porque, precisamente en eso consiste la POO; al hacer eso ests ocultando informacin y evitando que tus variables puedan tomar valores no deseados, limando, en gran medida, fallos de paso de valores a las variables, tan comunes en la programacin tradicional. Pese a que todo esto es lo ideal, no os "asusteis". Como ya veremos, tambin podemos acceder a las variables que tengamos directamente, sin tener que llamar a una funcin que se encarge de ello, pero, como ya he intentado recalcar, esto se debe de evitar siempre.

Herencia La herencia es otro de los pilares sobre los que descansa la POO. Gracias a la herencia, podemos hacer que todas las clases que tengamos, o las que nos interesen, puedan estar conectadas entre s, aprovechando, unas de otras, diversas caractersticas bsicas. La idea de la herencia parte de poder tener un diseo en el que todo se vaya descomponiendo en mdulos o problemas que van de lo ms general a lo ms especfico y que a su vez, estn conectados entre s. Quizs, este concepto va a quedar mejor explicado si se utiliza un ejemplo, as que vamos alla. Imaginaros que se quiere construir una aplicacin sobre las clases coche_turismo y coche_formula1. Para hacer esto mediante POO, tenemos 2 opciones, no utilizar la herencia o utilizarla. En caso de no utilizarla, bastara con construir los objetos que de cada uno de los vehculos terrestres coche_turismo y coche_formula1, sin embargo, pese a que esta solucin es vlida, es bastante mala a la hora de utilizar las posiblidades que nos ofrece la POO, ya que se da pie a utilizar la herencia y no la utilizamos.

2 de 3

30/01/2012 10:58 a.m.

http://macedoniamagazine.frodrig.com/poo2.htm

Fijmonos que tanto el coche_turismo como la coche_formula1 son vehculos terrestres y como tales tienen unas cosas en comunes y otras que no lo son. Por qu no construir una clase que contenga aquellas variables o atributos comunes para que sean heredados por las clases coche_turismo y coche_frmula1?. Esta es la solucin ms lgica, ya que, adems de permitir un ahorro de memoria, clarifica todo de una forma bastante aguda. Por todo esto, lo ms lgico sera consturir una clase general que tuviera los atributos o variables acerca del tipo de ruedas, velocidad y tipo de motor. Esta claro que cualquier coche ya sea un turismo o de carreras disfruta de esos datos. Por otro lado, tambin habr datos que sern especficos de la clase coche_turismo y de la clase coche_formula1, es decir, que habr datos que pueda tener uno y no los tenga el otro. El caso ms claro es el de pasajeros. Mientras un turismo puede llevar pasajeros, un coche de frmula 1 no puede llevar pasajeros (a parte del conductor, claro), es por esto, que podramos meter, y as hemos hecho, una variable de ese tipo en la clase coche_turismo. Como todo esto de la herencia queda mejor con un grfico ah va lo que os quiero decir mediante el ejemplo descrito:

En el ejemplo de arriba slo he tratado para un par de clases pero, como veremos en sucesivos captulos, la herencia nos permitr construir perfectas jerarquas de clases que nos ayudarn a partir de una idea general y llegar a algo concreto y de fcil tratamiento. Pese a que la POO descansa sobre otros importantes pilares, quizs ser demasiado prematuro hablaros de ellos ahora, lo importante es que se vaya cogiendo una idea general con lo visto en este captulo. Saber que es un objeto y que una clase, as como las caractersticas y ventajas que aporta una encapsulacin de datos y funciones junto a la posiblidad de desglosar nuestros problemas a modo de jerarquas mediante herencias, son cosas suficientes como para ir haciendose una idea de los mecanismos de la POO. En los sucesivos captulos, ya nos meteremos "ms a fondo" y pondremos listados y ejemplos en cdigo C++.

[Aula Macedonia] [Curso de POO en C++]

AULA MACEDONIA a MACEDONIA Magazine

3 de 3

30/01/2012 10:58 a.m.

http://macedoniamagazine.frodrig.com/poo3.htm

Curso de Programacin Orientada a Objetos en C++


Artculo realizado por Fernando Rodrguez.

Captulo 3. Novedades del C++ frente al C. Este captulo va a estar dedicado a ver alguno de los campos que ampla el lenguaje C++ frente al C. De todos es sabido que, el C++, es una ampliacin al C no slo por la nueva metodologa que incorpora sino por una serie de caractersticas que nos van a permitir programar de un modo mucho ms cmodo y potente. Pese a que en el captulo actual no vamos a ver todas las caractersticas, s que vamos a "abordar" la primera mitad. La otra, se la voy a reservar a todo lo que significa el uso de las clases en C++ cmo forma o camino para entrar "de lleno" en la programacin orientada a objetos. Sin ms prembulos, comenzamos a meter "caa" a la primera de las novedades. Las primeras novedades y ampliaciones. Como citaba al comienzo, en este captulo no vamos a hacer el estudio del tipo de datos clase pues, a todas luces, merece un estudio en exclusiva dada su gran importancia en lo que es la POO en C++. De todos modos, lo que s vamos a hacer va a ser ver dos especificadores de tipo que vienen del C y han sido ampliados en el C++, esto es, vamos a ver el tipo de datos enum y struct. Despus de que entendamos cmo funcionan las novedades en los anteriores especificadores, haremos una parada en el tipo de datos referencia pues, veris, que va a suavizar, en cierto modo, el uso de punteros. Eso s, antes pasaremos a comentar la utilidad de dos objetos como son cin y cout y, ya al final, os comentar si no lo habis descubierto para entonces, una nueva manera de insertar comentarios en nuestros programas. Para empezar, muchos de vosotros os habris empezado a preguntar Pero qu demonios son los especificadores de tipo?, bueno, pues todos lo sabis ya que no son ms que las palabras clave con las que definimos los distintos tipos de datos. As, int es un especificador de tipo que define un entero o, char, un especificador que hace lo propio definiendo un tipo de dato carcter. Pero hay ms como ya sabris, float, double, etc. Una vez "aclarado" el concepto pasamos a la explicacin de enum y struct como ampliaciones a lo que vena con el C, junto con la explicacin dedicada a las variables de tipo referencia. Una leve, pero interesante, mejora en enum. Como seguro que muchos de vosotros no habis utilizado mucho este tipo de datos en C, voy a realizar un breve recordatorio de su utilidad. Las constantes enumeradas o definicin de un tipo enumerado consiste en la definicin de un nuevo tipo de datos cuyo rango de valores se define, a su vez, por medio de una lista de constantes, es decir:
enum boolean(FALSE, TRUE); enum semana (LUNES=1, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO); enum salidaprintf(TABULADOR ='\t', NUEVA_LINEA='\n');

1 de 7

30/01/2012 10:54 a.m.

http://macedoniamagazine.frodrig.com/poo3.htm

Recodaris que, adems, las constantes enumeradas toman como valores por defecto 0,1.... a no ser que nosotros indiquemos lo contrario, como podis ver en el ejemplo con los das de la semana en los cuales adems de hacer que se empiece en 1, el resto de los valores se van a ir asignando de forma automtica. Pues bien, en C++, la palabra clave enum se va a ver incrementada en flexibilidad pues pasa a ser un especificador de tipo real. Ya se que para muchos esto no puede tener gran "significado", pero tenis que tener en cuenta que las constantes enumeradas, o lo que es lo mismo enum, puede considerarse como una seria alternativa a las macros definidas con #define y adems, podemos utilizar en C++ el especificador sabiendo que es de tipo real. Nuestras posibilidades se ven incrementadas notablemente. Ampliaciones importantes en struct De todos es sabido que las estructuras (struct) tienen una importancia vital en la programacin pues nos permiten construir complejas "aglutinaciones" de datos que nos van a permitir, despus, trabajar con "tablas de datos" distintas de un modo fcil y directo. Cuando utilizbamos las estructuras en C, no estbamos utilizando un tipo de datos completo, es decir, cuando definimos algo as en C
struct Guerrero { char *nombre; int fuerza; int resistencia; int experiencia; int edad; };

y queramos crear alguna variable de tipo Guerrero, tenamos dos opciones. Una de ellas era definir la variable de este modo:
struct Guerrero jugador1;

y la otra, la final de la estructura poniendo el nombre de las variables en la misma definicin, es decir:
struct Guerrero { char *nombre; int fuerza; int resistencia; int experiencia; int edad; } jugador1;

En ambos casos, tenamos una variable de tipo Guerrero que era, a su vez, de tipo estructura. La nica pega de todo esto es que no vamos a definir un tipo de datos nuevo en el sentido estricto de la palabra, esto es, siempre definimos estructuras no tipos de datos. Con la llegada del C++, las estructuras pasan a ser tipos de datos completos pudindose definir directamente variables del tipo estructura. Volvamos a poner la definicin anterior:
struct Guerrero { char* nombre; int fuerza; int resistencia; int experiencia; int edad; }

Ahora, para declarar una variable de tipo Guerrero slo tenemos que hacer lo siguiente:

2 de 7

30/01/2012 10:54 a.m.

http://macedoniamagazine.frodrig.com/poo3.htm

Guerrero jugador1;

Como podis comprobar ahora la creacin de variables del tipo estructura anterior es idntica que cuando hacemos lo propio con un especificador entero, carcter, etc. Si recordis lo ms parecido en C lo conseguamos con la palabra reservada typedef. Sin embargo, no slo se ha convertido a struct en un tipo de datos completo sino que, adems y como mayor diferencia, las estructuras en C++ pueden contener funciones junto a los datos de toda la vida. As, ya tenemos que empezar a diferenciar el contenido que se puede encontrar en una estructura, por un lado tendremos las variables de miembro que sern todas aquellas variables contenidas en la estructura y, por otro lado, tendremos las funciones miembro que, al encontrarse ms relacionadas con las clases las veremos cuando lleguemos a ellas. De esta manera, recordad que las estructuras en C++ son un tipo de datos completo y nos permiten definir variables de una manera mucho ms ptima. Sabed tambin que podemos incluir funciones (llamadas funciones de miembro) dentro de las estructuras, esto es, junto a las variables (llamadas variables de miembro) que siempre hemos sabido que debemos definir. De todos modos, como ya dije anteriormente, no estudiaremos por ahora las capacidades derivadas de poder utilizar tales funciones incluidas en las estructuras. Por ahora, basta con conocer, por encima, las novedades. Por si alguno se lo estaba preguntando, el acceso a las estructuras sigue siendo el mismo, esto es, utilizando el punto (.). En el caso de que tengamos punteros a estructuras, podremos utilizar la flecha de toda la vida, (->). Ya acabando con las estructuras, si os habis fijado en la ltima definicin que se realiz del tipo de datos Guerrero para mostrar el ejemplo de uso en C++, veris que la variable nombre es un puntero y que se define con el * despus del tipo de variable, esto es, despus del char. Esto es as porque es la metodologa tpica del C++ si bien, los que no queris utilizarla podis seguir definiendo las variables como en C, es decir, con el operador unario * justo antes del nombre de la variable. cout y cin dos novedades muy interesantes. A la hora de trabajar con C++ la construccin cout << se suele utilizar para la salida de datos apartando a un lado las funciones de la familia printf del C tradicional. Debemos de tener claro que cout no es ms que un objeto al cual le mandamos la informacin numrica y de texto mediante el smbolo <<. Esto es as porque en la representacin de cout << el operador << est sobrecargado para actuar de tal modo que se escriban en la salida estndar el contenido de cout. En los sucesivos captulos del curso de C++ se expondrn todos los pormenores de lo que es la sobrecarga de operadores de todos modos y como avance hasta que lleguemos aclarar que gracias a la sobrecarga de operadores nos podemos permitir "personalizar" smbolos de operaciones como son +,-,= y ++ para que se comporten de forma distinta cuando se utilicen con objetos de clases tambin diferentes, sirva esta breve introduccin. Es fcilmente imaginable que si podemos enviar datos a la salida mediante cout tambin existir en C++ un objeto similar pero para realizar entradas. El objeto en cuestin ser cin y su funcionamiento ser muy sencillo pues slo deberemos de utilizar el formato explicado ms arriba para cout. Es la operacin clsica de un scanf. As, si quisisemos realizar una peticin de una variable entera, por poner un ejemplo, podramos poner este cdigo (de paso aprovecho y meto un ejemplo con cout):
#include <iostream.h> // Ejemplo de utilizacin de cin y cout void main(void) { int valor; cout << "\nIntroduce un valor entero"; // equivalente a hacer scanf("%d",&valor); cin >> valor; cout << "\nHas introducido el valor " << valor; }

Como podis observar no hay ningn misterio de utilizacin de estas dos novedades del C++.

3 de 7

30/01/2012 10:54 a.m.

http://macedoniamagazine.frodrig.com/poo3.htm

Antes de pasar a las referencias, daros cuenta que para trabajar con cin y cout, debemos de utilizar siempre el archivo de cabecera "iostream.h". Podis tomroslo por el equivalente a "stdio.h" del C. Las referencias. Las referencias son novedades absolutas del C++ (no se encuentran disponibles en C). Una referencia es un nuevo tipo de datos que nos va a permitir utilizar las caractersticas de los punteros pero tratndolos como variables ordinarias. Podis imaginaros una referencia como un "alias" de una variable o, mejor dicho, como la misma variable disponible pero con un nombre distinto. Vaya lo no? ;). Pasemos a explicar cmo se utilizan las referencias para no armarnos tanto "bollo" en nuestra cabeza "programadora"... La inicializacin de una referencia es bien fcil ya que slo tendremos que asociar la referencia que deseemos a otra variable que ya est creada por nosotros. Una vez que hemos realizado tal inicializacin, la referencia va a estar continuamente asociada con su variable correspondiente. Cabe aadir que, si quisiramos hacer que nuestra referencia fuese el "alias" de otra variable o lo que es lo mismo que referenciase a otra variable no podramos, tendramos un error de compilacin. La declaracin de una referencia es bien sencilla:
// dato es una variable definida por // nosotros y es de tipo entero. int dato; // referenciaDato es la referencia que hemos creado. int& referenciaDato = dato;

Como podis observar para crear una referencia no necesitamos ms que la variable a la que queremos referenciar, que en el ejemplo es dato, junto la referencia en s que se va a definir con el smbolo &. De este modo, referenciaDato es la referencia o alias de la variable dato. Una vez hechas las dos operaciones anteriores cualquier cambio que hagamos sobre dato se ver reflejado en referenciaDato y viceversa, es decir, si realizamos una modificacin en referenciaDato, esta tambin se va a ver reflejada en la variable dato. Pongamos un ejemplo de todo esto!.

#include <iostream.h> void main() { int dato = 50; int& refDato = dato; cout << \n; cout << "La variable dato vale " << dato << \n; "La variable refDato vale " << refDato << \n;

cout <<

// multiplicamos la variable // dato por 2, ahora dato = 100 dato *= 2; cout << cout << "La variable dato vale " << dato << /n; "La variable refDato vale " << refDato << \n;

// incrementamos el valor de la // referenicia, ahora refDato = 101; refDato ++; cout << "La variable dato

4 de 7

30/01/2012 10:54 a.m.

http://macedoniamagazine.frodrig.com/poo3.htm

vale " << dato << \n; cout << "La variable refDato vale " << refDato; }

Si ejecutis este programita veris que la salida que se obtiene sera:


50 50 100 100 101 101

Con lo que deducimos que los cambios efectuados en dato y refDato se ven involucrados. Debis de saber que tanto dato como refDato comparten la misma direccin de memoria y por eso, cualquier cambio que efectuemos sobre dato afectar a refDato del mismo modo que si lo hiciramos al revs. Para cercioraros de que tanto la variable como la referencia poseen la misma direccin tan slo tenis que ejecutar este listado que os muestro a continuacin y comprobar que la direccin de dato y refDato es la misma.

#include <iostream.h> void main() { int dato = 50; int& refDato = dato; cout << \n << "La direccin de la variable dato es " << &dato << /n; cout << \n << "La direccin de la referencia refDato es " << &refDato << \n; }

Si lo ejecutis veris que salen los mismos valores. Una de las cosas que tenemos que tener bien claro es la utilizacin del operador unario & con una variable y con una referencia. Cuando declaramos una referencia estamos definiendo un tipo de datos que es exclusivo del C++, en este caso, el operador & va junto al tipo de datos que estamos definiendo como referencia as, si nosotros queremos crear una referencia que va a referenciar a una variable de tipo entero pondremos algo como int& referencia. Otro uso bien distinto es cuando lo que queremos obtener es la direccin en memoria de cierta variable o dato. En este caso tanto en C como en C++ el operador unario & se comporta de igual modo dndonos la direccin en memoria de tal variable o dato. Tan slo tenis que ejecutar el ltimo de los listados expuestos el cual nos mostrar, por pantalla, la direccin en memoria de una variable de tipo entero y la de una referencia que tiene con alias precisamente tal variable de tipo entero. Referencias y punteros. Todo lo que hacamos con punteros lo podemos realizar con las referencias de un modo mucho ms intuitivo. Pese a que nosotros cuando trabajamos con las referencias lo hacemos como si de otra variable ms se tratara, el compilador lo que realmente est haciendo es utilizar esa referencia como un valor asociado a la direccin en memoria de la variable en cuestin, es decir, nosotros utilizamos las referencias como si de otra variable ms se tratar mientras que el compilador realmente las utiliza como los tan temidos e importantes punteros del C. Como lo mejor para ver esto es con un ejemplo ahora os muestro cmo realizar el cambio del valor de una variable local desde una funcin con C, es decir, con punteros y, despus, la versin en C++ utilizando las referencias.

5 de 7

30/01/2012 10:54 a.m.

http://macedoniamagazine.frodrig.com/poo3.htm

#include <stdio.h> /* Prototipo de la funcin para cambiar valor */ void CambiaVble (int *punt); void main(void) { int vble = 50; printf("/n El valor de vble es %d",vble); CambiaVble (&vble); printf("\n El valor de vble es %d",vble); } void CambiaVble (int *punt) { *punt = 0; } Esta es la forma tradicional de trabajar en C y la salida debera de ser
El valor de vble es 100 El valor de vble es 0

Pasemos ahora a ver cmo hacer lo mismo pero utilizando referencias.


#include <iostream.h> /* Prototipo de la funcin para cambiar valor */ void CambiaVble (int& ref); void main(void) { int vble = 50; cout << "\n El valor de vble es " << vble; CambiaVble (vble); cout << "\n El valor de vble es " << vble; } void CambiaVble (int& ref) { ref = 0; }

Si os fijis bien y llevis un tiempo trabajando con punteros en C veris que realmente el utilizar referencias es como utilizar cualquier otro tipo de variable y esto ltimo hace que los "escabrosos" punteros se vuelvan mucho ms sencillos de utilizar para el programador. Estos dos listados lo he realizado pensando en mostrar como ejemplo de comparativa entre punteros y referencias con lo que muy pocas ventajas pueden ser sacadas de ellos. Pese a que su uso es muy recomendado, hay que tener cuidado especialmente cuando uno empieza a codificar un programa de cierta envergadura en el cual, rpidamente comienzan a crecer variables, constantes y dems parmetros que pueden "ocultar" a nuestras referencias. Cuando trabajbamos en C siempre sabamos localizar un puntero por el hecho de llevar siempre el operador unario como identificativo frente al resto de variables de nuestra creacin. Con todo esto quiero decir que una referencia no tiene que ser identificada utilizando ninguna clase de smbolo especial y que puede ser confundida como una variable ms pasando por alto el gran "poder" contenido en ella. Las referencias, en definitiva, deben de ser utilizadas cuidadosamente procurando en todo lo posible, poner algn comentario explicativo que nos identifique rpidamente que eso a lo que vamos a "tocar" no es una variable como otra cualquiera sino la citada referencia. Estis avisados, se pueden meter muchas patadas con esto... Los comentarios en C++

6 de 7

30/01/2012 10:54 a.m.

http://macedoniamagazine.frodrig.com/poo3.htm

Ya para finalizar este captulo vamos a echar un vistazo a la novedad referida al formato con el que podemos incluir nuestros comentarios. Como ya habris podido observar a lo largo de todos los ejemplos incluidos, los comentarios en C++ se van a poner justo despus de que pongamos las dos barras invertidas //. Esta forma de poder poner los comentarios nos va a permitir trabajar de una forma mucho ms cmoda y rpida para poner nuestras anotaciones. Lgicamente tambin podemos seguir utilizando las clsicas /* */ para dejar nuestros apuntes en el cdigo. Y se acab el captulo. Pues s, ya hemos concluido este segundo captulo de POO. Hay alguna que otra cosa que me hubiera gustado comentar como era el caso del uso de cualificadores, esto es, const y todas sus aplicaciones as que no os estrais si lo meto en un apndice. Para la siguiente entrega de Macedonia, espero poder volver con ms cosas entre las cuales estar, sin duda, el captulo sobre las Clases.

[Aula Macedonia] [Curso de POO en C++]

AULA MACEDONIA a MACEDONIA Magazine

7 de 7

30/01/2012 10:54 a.m.

http://macedoniamagazine.frodrig.com/poo4.ht

Curso de Programacin Orientada a Objetos en C++


Artculo realizado por Fernando Rodrguez.

Captulo 4. La piedra angular del C++: las clases. Con este tercer captulo del curso sobre C++, empezaremos a ver las clases, autnticas piedras angulares para la programacin en C++. Mediante las clases, como veremos ms adelante, podremos valernos de una de las propiedades ms importantes y fundamental de toda programacin orientada a objetos, esto es, la encapsulacin. Recordemos que la encapsulacin haca referencia a la capacidad de mezclar datos (variables, constantes, etc) junto a funciones (a partir de ahora, llamaremos a estas funciones mtodos), de tal forma que los mtodos trabajen con los datos. Introduccin: creando una clase Una clase la podemos entender como una estructura en la que, adems de poder incorporar variables, tambin se puede hacer lo propio con funciones. Supongamos la siguiente estructura que utiliza el mecanismo de la encapsulacin: struct Guerrero { char *m_nombre; int m_fuerza; int m_resistencia; int m_experiencia; void AsignaNombre (char *nombre); void IncrementaExperiencia (int tipo_atributo); void MuestraDatosPersonaje (void); }; Como podis observar, la estructura guerrero sigue las normas bsicas de toda estructura que conocemos del C tradicional salvo, claro est, esas tres funciones. Sin embargo, pese a que es posible definir estructuras de este modo en C++ y comenzar a trabajar con objetos, en la prctica no se utiliza struct de este modo, es decir, para definir estructuras como las de arriba en las que se mezclan variables con funciones de miembro se utilizan las clases. Para definir una clase no tenemos que ir muy lejos, basta con cambiar la palabra struct por class y ya lo habremos logrado, mirad: class Guerrero { char *m_nombre; int m_fuerza; int m_resistencia; int m_experiencia;

de 9

30/01/2012 10:59 a.m

http://macedoniamagazine.frodrig.com/poo4.ht

void AsignaNombre (char *nombre); void IncrementaExperiencia (int tipo_atributo); void MuestraDatosPersonaje (void); }; El uso de clases frente a estructuras radica en que con las primeras podemos utilizar mecanismos tan vitales y fundamentales como la herencia y otras importantes propiedades de la orientacin a objetos. Pasando a analizar ms de cerca la clase guerrero definida ms arriba, veremos enseguida que hay un total de cuatro variables de miembro. Dichas variables de miembro llevan todas una "m" seguida de un subrayado esto es as porque se suele utilizar este convenio para distinguir variables que son de miembro, como es el caso, de variables que no pertenecen a una clase (por ejemplo una variable cualquiera definida en el main). Puede que todos estos detalles os sean molestos. Podis prescindir perfectamente de ellos pero yo os recomiendo que seis siempre ordenados. Pensad que si no estis an metidos en la programacin en Windows, la colaboracin para realizar programas en equipo no la habis vivido muy de cerca pero, tarde o temprano, os tocar tener que trabajar con un equipo estable de personas o cdigo que no es vuestro, por eso, es muy importante aprender a construir cdigo que no slo funcione (y adems lo haga bien) sino que sea entendible por otros. Volviendo al anlisis de la clase guerrero, veamos como definamos cuatro variables pero, adems, tambin insertbamos la definicin de tres mtodos que eran: void AsignaNombre (char *nombre); void IncrementaExperiencia (int tipo_atributo); void MuestraDatosPersonaje (void); Como veremos ms adelante ser con estos mtodos con los que realizaremos el trabajo de nuestras variables anteriormente creadas. Se acab eso de tratar las variables por separado, ahora, para una simple insercin deberemos de utilizar una funcin que lo haga. Cuando declaramos una clase no se reservar memoria hasta que creemos un objeto de la clase, la creacin de un objeto de una clase se llamar instanciar un objeto y, a su vez, un objeto creado de una clase se denomina instancia de esa clase. Releer si no habis captado todo porque ser importante tener las cosas ms o menos claras a partir de ahora. Protegiendo el acceso a la clase Un aspecto muy importante de la programacin orientada a objetos es el tema de la seguridad y el control de acceso a los miembros de datos de la clase. Para poder definir en qu medida las variables y funciones miembro pueden ser accedidas, vamos a poder establecer unas prioridades de acceso. Con este aspecto vamos a erradicar, entre otras cosas, los problemas que nos solan ocasionar las variables globales del C tradicional, esto es, efectos laterales, cambios inadvertidos de valor, etc. Existen tres especificadores de acceso posibles que son public, protected y private. Antes de ver un ejemplo de cada uno de ellos, citaremos que cuando se declara pblico (public) un miembro de una clase, tanto si es funcin como si es variable, este se podr acceder desde dentro de la propia clase como desde fuera de ella. Cuando declaramos miembros protegidos (protected) nos aseguramos que slo sern accesibles desde las funciones de miembro de la clase siendo imposible el acceso tanto desde otras clases como desde cualquier otra parte del programa. Finalmente, un especificador privado (private), no permite que las clases sean accedidas ni desde otras clases, ni desde otras partes del programa ni desde clases derivadas (que ya las veremos ms adelante). Funciones de miembro intercaladas o en lnea. Antes de pasar al primer "gran" ejemplo de este captulo, veremos qu son las funciones de miembro intercaladas o en lnea. Las funciones intercaladas, no son ms que las funciones de miembro definidas en la clase y que, adems, tambin contienen su cdigo en la misma clase. Estas funciones se caracterizan porque ocupan muy pocas lneas de cdigo de tal manera que, para evitar la sobrecarga computacional que puede ser la llamada a una funcin cuando realmente el cdigo a ejecutar es mnimo, caso de estas funciones, se permite que dichas funciones o mtodos se "inserten" en todos aquellos lugares en los que son necesitadas, crendose una copia de ellas mismas dentro del cdigo

de 9

30/01/2012 10:59 a.m

http://macedoniamagazine.frodrig.com/poo4.ht

en las zonas en las que se necesitan. Con esto ganamos en rapidez pero tambin tamao en nuestros programas ejecutables ya que vamos a tener repetidas copias en el ejecutable de la funcin en cuestin. De todos modos, merece la pena hacer el ejecutable final un poco ms grande si con ello ganamos en rapidez, por ello, es aceptable utilizar las funciones intercaladas. Un tpico ejemplo de funcin intercalada podra ser aquella que en una clase se dedica a dar valor a una variable de miembro, es decir, aquella que se limita a realizar una asignacin. Recordando el ejemplo de la clase guerrero podramos definir la funcin AsignaNombre de forma intercalada. Para llevar esto a cabo existen dos mtodos. El primero consiste en realizar la definicin y cuerpo de la funcin en la misma lnea, dentro de la definicin de la clase. La otra sera la utilizacin de la palabra reservada inline que no veremos hasta ms adelante del curso. Por ahora nos bastar ver un breve ejemplo de cmo podra quedara nuestra clase guerrero si definiramos como intercalada la funcin encargada de asignar un valor a la variable nombre: class Guerrero { char *m_nombre; int m_fuerza; int m_resistencia; int m_experiencia; void AsignaNombre (char *nombre) {m_nombre = nombre;} void IncrementaExperiencia (int tipo_atributo); void MuestraDatosPersonaje (void); }; Como podis observar la funcin intercalada sigue todas las normas de definicin de las funciones tradicionales, esto es, cabecera de la funcin y, a continuacin, cuerpo de la misma encerrada entre llaves. De este modo, ya vemos y confirmamos una serie de cosas muy importantes: Las clases nos permiten encapsular datos (variables de miembro) y funciones para trabajar con esos datos (mtodos). Podemos definir mtodos intercalados cuando el trabajo de los mismos es mnimo. Una forma de hacerlo consiste en escribir la cabecera y el cuerpo en la misma lnea y dentro de la clase. Debemos de trabajar con las variables de miembro mediante los mtodos que creemos en la clase, es decir, hay que evitar hacer Nombre_Objeto.m_nombre = nombre, es decir, a menos que no estemos "ensayando" el acceso directo a las variables de una clase debern de realizarse mediante los mtodos adecuados para ello. Lo correcto, como digo, es definirnos una funcin de miembro que se encargue de esa tarea. En nuestro ejemplo de clase el mtodo AsignaNombre trabaja con la variable de miembro m_nombre asignndole un valor. Vamos a repasar todo con un ejemplo. Antes de continuar escribiendo, vamos a realizar un ejemplo de implementacin de una clase, creacin de una instancia a dicha clase (creacin de un objeto) y, por ltimo, utilizacin de la clase a travs del objeto creado. El ejemplo ser bien sencillo. Construiremos una clase guerrero en la que, como si se tratar de un juego de Rol (infinitamente primitivo...), seremos capaces de ir asignando valores a datos como la edad, la fuerza, la destreza, la energa o el nombre. Por supuesto, podremos ser capaces de volcar dicha informacin a pantalla. Despus, podremos crear tantas instancias u objetos como queramos de ese tipo, tantos como guerreros queramos manejar... All vamos!. #include <iostream.h> class Guerrero { private: char *m_nombre; int m_edad; int m_fuerza; int m_destreza; int m_energa;

de 9

30/01/2012 10:59 a.m

http://macedoniamagazine.frodrig.com/poo4.ht

public: void MuestraDatos(void); void PonerNombre (char *nombre) {m_nombre = nombre;} void PonerEdad (int edad) {m_edad = edad;} void PonerFuerza (int fuerza) {m_fuerza = fuerza;} void PonerDestreza(int destreza){m_destreza=destreza;} void PonerEnergia (int energia) {m_energia = energia;} char * DevuelveNombre (void) {return m_nombre;} int DevuelveEdad (void) {return m_edad;} int DevuelveFuerza(void) {return m_fuerza;} int DevuelveDestreza(void) {return m_destreza;} int DevuelveEnergia (void) {m_energia = energia;} }; void Guerrero::MuestraDatos(void) { cout << "Nombre del personaje: " << m_nombre << \n; cout << "Edad: " << m_edad << \n; cout << "Fuerza: " << m_fuerza << \n; cout << "Destreza: " << m_nombre << \n; cout << "Energa: " << m_energia << \n; } void main (void) { // Creamos un objeto o instancia llamado Conan Guerrero Conan; // Ahora le vamos dando valores al personaje Conan.PonerNombre ("Conan"); Conan.PonerEdad (23); Conan.PonerFuerza (40); Conan.PonerDestreza (20); Conan.PonerEnergia(150); // Y ahora vemos por pantalla el resultado Conan.MostrarDatos(); } En este corto ejemplo podemos ver ya el funcionamiento de la programacin orientada a objetos desde su nivel ms bsico. En un primer lugar podemos distinguir la creacin de la clase Guerrero. Apreciamos una parte privada en donde definimos las variables que slo podrn ser accesibles por las funciones de la clase y una parte pblica a la que s se podr acceder desde fuera (desde el main en este caso). As, para poder asignar un valor no se nos permitir hacer libremente algo como: Conan.m_nombre = "Conan"; Si hacemos esto el compilador mostrar un error y no dejar que se acabe la compilacin del ejemplo. Para hacer tales cosas, disponemos de funciones definidas como intercaladas o en lnea dentro de la propia clase. Esto es as porque como vimos en una seccin ms arriba, las funciones de asignacin de datos a las variables, en este caso, son de una sencillez tal que merece la pena utilizar funciones en lnea. Por otro lado, estn declaradas como pblicas con lo que, al llamarlas desde el main, no producen error alguno en tiempo de compilacin. Otras funciones que tambin se definen pero no se utilizan son las referentes a la devolucin de los datos de las variables de miembro. Realmente las he puesto para recalcar, an ms, que TODAS las operaciones con variables hay que realizarlas a travs de funciones de miembro y que si, por ejemplo, slo quisiera mostrar por pantalla la edad del guerrero creado pues debera de obtenerla utilizando la funcin creada a tal efecto (en este caso en concreto sera Conan.DevuelveEdad(); ). En lo referente a la funcin void MostrarDatos(void); pues nos encontramos con el caso ms usual, la declaracin de funciones FUERA de la clase. Estas funciones sern las que ms implementemos. Para su utilizacin debemos de seguir

de 9

30/01/2012 10:59 a.m

http://macedoniamagazine.frodrig.com/poo4.ht

unos pasos muy sencillos. Slo debemos de poner el nombre de la clase a la que pertenecen (en el ejemplo es la clase Guerrero) seguido y sin espacios de dos puntos :: . Esta pareja de dos puntos recibe el nombre de operador de resolucin de mbito y es la manera ms usual para definir funciones de miembro fuera de la clase. Con ellos, el compilador sabe a qu clase corresponde la funcin que vamos a definir. Y ya para finalizar, despus del operador de resolucin de mbito, pondremos el nombre de la funcin de miembro. Tenis que tener en cuenta que, pese a que la funcin se implementa fuera de la clase, sta ya ha sido definida dentro de ella (tal y como haramos en C tradicional para definir funciones que no son la main. Recordemos que primero se definen encima del main, para implementarse despus, a continuacin de la funcin main). Una vez que ya tenemos definida la clase, slo hay que pasar a la funcin main y comenzar a trabajar con ella. Lo primero es crearnos un objeto o instancia de esa clase. Dicho objeto puede tener cualquier nombre y se crea como si la clase anteriormente definida fuera un tipo de dato, es decir, ponemos el nombre de la clase y despus el nombre del objeto que queremos crear de ese tipo de clase. En nuestro caso al objeto en cuestin le hemos llamado Conan (original s seor...). Una vez creado el objeto Conan procedemos a trabajar con l. Cmo es lgico, tendremos que inicializar sus valores. Para ello bastar con ir utilizando los mtodos de los que dispone. As, utilizamos PonerNombre, PonerEdad, etc hasta haber completado todos y cada uno de los atributos que debemos de inicializar. El resto es bien fcil pues slo tendremos que llamar al mtodo para mostrar los datos y as verlos en pantalla. Cabe destacar que, para poder acceder a los mtodos del objeto, deberemos de utilizar un punto entre el nombre del objeto y el mtodo en cuestin, es decir, como si Conan fuera una estructura de C. Esta sera la descripcin de un modo exhaustivo del ejemplo. Espero que se os hayan aclarado bastantes cosas sobre lo que hemos venido explicando con anterioridad. Por supuesto, an no hemos puesto sobre la mesa todo lo que hemos visto. Por ejemplo, an no hemos hecho un ejemplo real que implemente herencia. Constructores y destructores Los constructores y destructores son una forma efectiva de inicializar y dar por concluida, respectivamente, la utilizacin de una instancia u objeto que hemos estado utilizando hasta ahora. Un constructor se puede tomar como un mtodo que se llama nada ms que creamos un objeto o instancia y que se encarga de "preparar", por as decirlo, la utilizacin del mismo ya sea inicializando valores bsicos, asignando memoria para trabajar, etc. En cuanto a los destructores, pues podemos entenderlos como los mtodos que se llaman automticamente cuando deseamos eliminar un objeto creado con anterioridad (por ejemplo, al acabar un programa todos los objetos que hemos creado al comienzo del mismo se eliminarn) encargndose de liberar todos los posibles recursos asignados al mismo como puede ser memoria. Los Constructores siempre se llaman nada ms realizar una instancia y cumplen la propiedad de llevar el mismo nombre de la clase a la que pertenecen, es decir, un constructor de la clase casa tendra el mismo nombre, esto es, se llamara casa tambin. Esto podra ser algo as: class Casa { public: Casa(); // Constructor ........ } Si creramos un objeto chalet de tipo Casa en nuestro programa: Casa chalet; El mtodo constructor se llamara automticamente si necesidad de que nosotros hiciramos chalet.Casa(); . Hay que aadir, finalmente, que dentro de una clase slo puede existir un constructor. El tema de los destructores es idntico en funcionamiento slo que, en lugar de ser llamados automticamente al crear el objeto, son llamados cuando ste se destruye. Un objeto se puede destruir si es dinmico o, de forma ms fcil, si llegamos al final del main dentro del programa en el que lo habamos utilizando. Los destructores se definen con el mismo nombre de la clase, al igual que los constructores, pero con la notable diferencia de llevar delante del nombre el smbolo ~ (ALT - 126), sera algo as (continuamos con el mismo ejemplo de clase):

de 9

30/01/2012 10:59 a.m

http://macedoniamagazine.frodrig.com/poo4.ht

class Casa { public: Casa(); // Constructor ~Casa(); // Destructor ........ } Las caractersticas que s distinguen a un destructor de un constructor son dos: un destructor nunca devuelve nada y tampoco puede recibir parmetro alguno. La implementacin tanto de constructores como de destructores sigue las normas ya vistas ms arriba para definir una funcin de miembro de una clase. Podemos optar por realizar implementaciones intercaladas o in line o bien, podemos definirlas fuera del cuerpo de la clase utilizando para ello el operador de resolucin de mbito (::). Por ejemplo, el esquema de la implementacin del constructor de la clase anterior utilizando el operador de resolucin de mbito sera: Casa::Casa() { // Aqu pondramos el // cuerpo de la funcin constructor } Y en el caso del destructor: Casa::~Casa() { // Aqu pondramos el // cuerpo de la funcin destructor } Los constructores y destructores siempre se encuentran dentro de una clase aunque nosotros no los hayamos definido, es decir, en nuestro ejemplo de ms arriba, en el que implementamos una clase llamada guerrero, no definimos ningn constructor ni tampoco ningn destructor sin embargo, s que existan. Cuando nosotros creamos una instancia a un objeto, el compilador siempre llama a un constructor. En el caso de que no exista, como pasa en el ejemplo de arriba, el compilador crea un sencillo constructor con el que instanciar nuestro objeto. Por tanto, al crear siempre el compilador un constructor por defecto en caso de no encontrar el nuestro, nosotros podemos "pasar olmpicamente" de molestarnos en crearnos uno, como vimos ms arriba. Esto mismo es aplicable a los destructores, es decir, cuando el objeto deja de "existir" y se elimina, bien por la finalizacin del programa o bien porque se trataba de un objeto dinmico y hemos decidido eliminarlo en el transcurso de ejecucin de nuestro programa, el compilador "ir" en la bsqueda del destructor que hayamos definido en la clase. Si no lo encuentra, no tendr ms remedio que utilizar el que cre automticamente cuando instanciamos el objeto por primera vez (el compilador cuando creamos el objeto se encarga siempre de comprobar la existencia de un destructor por eso, realmente cuando eliminamos un objeto ya sabe si lo que tiene que hacer es llamar al destructor que hemos creado o bien utilizar el que l mismo ha producido porque nosotros no tenamos ninguno listo). Puede parecer que la utilizacin de constructores y destructores es un "rollo" para el programador pero eso no es en absoluto cierto, es ms, llegan a ser en casi todas las ocasiones imprescindibles ya que nos posibilitan entre otras cosas, tareas tan importantes y vitales como la inicializacin de las variables del objeto nada ms instanciarlo. Recordemos que cuando creamos una clase y las variables an no han sido inicializadas (por ejemplo una variable entera no ha sido puesta a su valor inicial para que el objeto trabaje bien con ella) siempre contendr "valores basura". No me extender ms aqu porque es algo que ya supongo que conoceris de sobra. El caso es que, volviendo sobre el tema, los constructores, en particular, pueden ser muy tiles para estos casos de inicializacin de valores. Tambin hay otras razones ms "persuasivas". Un buen programador deber siempre suponerse lo peor (y ms acertado) y eso significa no confiar en que los compiladores nos generen... buenos constructores. Argumentos por defecto en funciones

de 9

30/01/2012 10:59 a.m

http://macedoniamagazine.frodrig.com/poo4.ht

Esta posibilidad resulta extremadamente til para aplicarla en la realizacin de constructores para nuestras clases. La creacin de funciones que incluyan argumentos por defecto nos permiten el poder invocar a una funcin sin necesidad de pasarle todos los parmetros que esta incluye ya que, en su defecto o ausencia, la funcin es capaz de asignar un valor ya definido a esa variable. Nos podemos imaginar que tenemos una funcin que dibuja crculos y que, en la casi totalidad de las ocasiones, dichos crculos comienzan en la posicin (10,10). Resulta muy til el poder llamar a la funcin y que, dependiendo de si sta detecta que recibe argumentos o no, sea capaz de asignar el valor que le pasamos a las coordenadas x e y o bien, darlas los valores (x=10,y=10). Ahora imaginmonos que esto se aplica al constructor de una clase. Vamos a suponer que la clase se llama crculo, para seguir con el mismo ejemplo. Cuando creemos un objeto o instancia de dicha clase, puede que nos interese que comience dibujando el crculo en una posicin distinta a (10,10) pero sabemos de antemano que en la prctica totalidad de las ocasiones, nada ms que creamos la instancia, queremos que, internamente, los valores de x e y queden inicializados a dichos valores. Para poder definir funciones que toman valores por defecto tan slo tenemos que hacer y poniendo el ejemplo del crculo: void SituaCirculo (int x = 10, int y = 10); En el caso de que no pasemos el parmetro en la zona de las x, por ejemplo, la funcin asignar a esta variable el valor 10. An ms, si no pasamos ningn argumento, las variables x e y quedarn inicializadas a x=10 e y=10. Veamos ahora un sencillo ejemplo en el que definimos una clase llamada Circulo (totalmente incompleta) que contiene una funcin de miembro para decirnos en qu coordenadas hemos situado el crculo utilizando las variables x e y. El constructor de dicha clase se encarga de dar valores por defecto a x e y en caso de no recibir ninguno cuando creemos la instancia: #include <iostream.h> class Circulo { private: int m_x, m_y; public: // Constructor Circulo (int xtemp = 10, int ytemp = 10) { m_x = xtemp; m_y = ytemp; } ~Circulo (){} // Destructor int DevuelvePosx (void) { return m_x; } int DevuelvePosy (void) { return m_y; } } void main (void) { // Aqu creamos un objeto con paso de parmetros Circulo circulo1(12,30); // Aqu acabamos de crear la instancia Circulo circulo2; cout << "La coordenada X << circulo1.DevuelvePosx cout << "La coordenada Y << circulo1.DevuelvePosy cout << /n ; cout << "La coordenada X de circulo 2 es " << circulo2.DevuelvePosx << \n; cout << "La coordenada Y de circulo 2 es " de << de << circulo 1 es " \n; circulo 1 es " \n;

de 9

30/01/2012 10:59 a.m

http://macedoniamagazine.frodrig.com/poo4.ht

<< circulo2.DevuelvePosy << \n; } Si ejecutamos el programa, este mostrara por pantalla: La coordenada X del circulo 1 es 12 La coordenada Y del circulo 1 es 30 La coordenada X del circulo 2 es 10 La coordenada Y del circulo 2 es 10 Para entender todo mejor he creado dos objetos. La instancia circulo1 se caracteriza por pasar al constructor unos valores alternativos mientras que circulo2 lo que hace es utilizar los valores por defecto. En fin, creo que no tiene mayor problema no?. Pues a lo siguiente Qu es el puntero this? El puntero this es una de las mltiples prestaciones que incorpora el C++ y que, adems, es ampliamente utilizada. Todo objeto que nosotros creamos en C++ posee un puntero llamado puntero this que tiene la particularidad de apuntar al objeto al que va ligado. As el objeto se va a encontrar "apuntado as mismo" mediante el puntero this. Adems, siempre que dentro del programa llamamos a una funcin de miembro, el puntero this se pasa en la llamada a la funcin. Con esto la funcin puede utilizar el puntero this para acceder a otros miembros (funciones o variables) de su misma clase. Como las funciones de miembro suelen utilizar el puntero this como un argumento al llamar a otras funciones, la funcin llamada puede, a su vez, utilizar el puntero this para acceder al conjunto de miembros del objeto de la funcin que la ha llamado.... qu lo!... Quizs lo mejor para poder entender el puntero this es ir "soltndolo" a medida que avancemos en el curso mediante la inclusin del mismo en ejemplos. De todos modos, baste el listado que voy a poner a continuacin para que os hagis una idea de lo que es el puntero this: #include <iostream.h> class Puntero_this{ public: // Constructor Puntero_this(void) {} // Destructor ~Puntero_this() {} // Devuelve el puntero this void* Devuelve_this(void) {return this;} }; void main (void) { // Puntero sin tipo void *puntero; // Creamos una instancia u objeto Puntero_this obj_this; // En puntero est el puntero this puntero = obj_this.Devuelve_this(); cout << "El valor de puntero es el del puntero this y vale " << puntero << \n; } El ejemplo es muy sencillo e ilustra cmo todas las clases que creamos tienen su propio puntero this. As, la clase Puntero_this tiene su propio puntero this que es devuelto mediante el mtodo intercalado llamado void* Devuelve_this

de 9

30/01/2012 10:59 a.m

http://macedoniamagazine.frodrig.com/poo4.ht

(void); Como vemos en el ejemplo, nos creamos un puntero void llamado "puntero" para contener el valor que nos devuelve la funcin anteriormente citada para despus mostrarlo en pantalla mediante un sencillo cout. Y en el prximo nmero.... Pues en el prximo nmero y al disponer de ms tiempo espero poder darle un gran empujn a este curso realizando dos captulos ms. Creo que lo ms importante es ofrecer la informacin lo ms extensamente posible y, aunque para un fanzine como Macedonia, le viene bien ir poco a poco para mantener contenidos siempre, no lo haremos... As que en el prximo nmero mucho ms!

[Aula Macedonia] [Curso de POO en C++]

AULA MACEDONIA a MACEDONIA Magazine

de 9

30/01/2012 10:59 a.m

http://macedoniamagazine.frodrig.com/poo5.htm

Curso de Programacin Orientada a Objetos en C++


Artculo realizado por Fernando Rodrguez.

Captulo 5. Jerarqua de clases y herencia en la prctica. Hasta ahora hemos tocado bastantes aspectos de forma puramente terica, tambin hemos dado nuestros primeros pasos construyendo programas en C++ que son capaces de aprovecharse de las ventajas que este leguaje nos dispensa frente al C tradicional. Es ahora ya de empezar a llevar a la prctica todo el aspecto terico o, mejor dicho, toda la nueva forma de pensar que impregna la metodologa orientada a objetos. En este captulo vamos a aprender a derivar clases y a utilizar la herencia en nuestros programas. Pronto veremos las grandes posibilidades que esto nos reporta para hacer diseos mucho ms robustos y flexibles y, sobre todo, aprenderemos a ir pensado en C++ cosa fundamental para saber trabajar con la POO. Recordad que la metodologa orientada a objetos no es slo una nueva forma de programar es, sobre todo, una nueva forma de pensar. Introduccin a la jerarqua y herencia de clases La derivacin de clases viene a significar crear una clase a la que denominamos clase base. En ella, definimos un conjunto de propiedades (atributos y mtodos) que consideramos que son los ms generales y que no deberan de faltar. Una vez que tengamos la seguridad de haber dado con la clase general que andbamos buscando, podemos crear otra clase que, en cierto modo, supone una especializacin de la anterior. Como es una especializacin de la anterior, adems de las propiedades definidas para la clase base tendr las suyas propias que servirn para diferenciarla de la anterior y para hacer que consiga esa especializacin que buscamos. Para hacer que tenga los atributos de la clase base tenemos que volver a escribir todo?. NO!, slo hace falta heredar de la clase base los atributos que nos interesen. Lo nico que tendremos que escribir nuevo sern los atributos que especializan a esta clase. A la clase que hereda de otra clase se le llama clase derivada. Arggg!!!, vaya lo que te estars formando en la cabeza, no?. Te recomiendo que eches un vistazo al grfico que voy a poner a continuacin y que luego vuelvas a leer la parrafada anterior.

1 de 9

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo5.htm

Deacuerdo?. Bueno, me supongo que no del todo as que voy a intentar ir aclarando todo esto poco a poco explicando qu son las jerarquas. Cuando una clase se deriva de otra clase, llamada clase base, lo que hace es heredar un conjunto de funciones o mtodos y variables de la clase base. No se heredan todos. Slo se heredan los elementos que estn preparados para ser heredados. As, si una funcin o variable en la clase base est declarada como privada no se podr heredar desde la clase derivada, es decir, no podremos acceder a ella y si lo intentamos, obtendremos un error en tiempo de compilacin. Hasta ahora slo hemos puesto el ejemplo de dos clases. Una la llamamos clase base y otra clase derivada. La segunda hereda los mtodos y variables que no son declarados como privados en la clase base sin embargo, puede la clase base ser heredada por ms de una clase derivada?, puede una clase derivada convertirse en clase base y que otras clases hereden de ella?. Ambas respuestas obtienen un gran S. Podemos tener una clase base y montones de clases derivadas. As mismo, puede darse el caso de una clase derivada de una clase base y una tercera clase que toma a la clase derivada como su clase base, derivndose de ella. Si esto lo llevamos a la prctica iremos obteniendo una jerarqua de clases. Un ejemplo?. Voy a poner un caso que bien podra darse para un sistema de generacin de personajes de un juego de rol (ahora bien, super primitivo...). Imaginaros que queremos hacer un sistema para la creacin de multitud de personajes. Estos personajes podrn ser slo humanos. Al ser humanos slo existirn dos sexos, hombre y mujer. Por otro lado, existen dos tipos de personajes: los Guerreros y los Magos. Cmo podramos montarnos un sistema jerrquico con todo estos datos?. Est claro que todos los personajes son humanos por lo tanto sera una buena idea partir de una clase llamada HUMANO que contuviera todos los atributos que tiene cualquier ser humano. Luego vemos que, al estar creando un sistema de generacin de personajes humanos, tenemos dos sexos independientes el del hombre y el de la mujer. Las diferencias son obvias pero no por ello hace falta crear dos clases distintas llamadas HOMBRE y MUJER pues no nos hacen falta tomar atributos exclusivos de los sexos para trabajar en la generacin de personajes. Basta con poner una variable en la clase HUMANO llamada sexo y dar el valor oportuno (por ejemplo si sexo se inicia con V significa que es un hombre y si se inicia con M significa que es una mujer. Internamente trabajaremos con 0 y 1). Lo que seguro necesita de clases nuevas es el tema de las dos especialidades de los personajes que podamos crear. Est claro que tanto los guerreros como los magos son humanos. Vamos a preguntarnos a nosotros mismos para ver si nos aclaramos las diferencias que pueden existir en cada uno de los personajes. Un guerrero tiene fuerza, inteligencia, destreza, energa, peso, sexo, edad y nombre?. S, y adems esto tambin lo tiene cualquier mago por lo tanto estas caractersticas ya han debido de ser incluidas en la clase HUMANO. Un guerrero utiliza un libro de hechizos para luchar?. No, un guerrero slo puede utilizar armas. Pero un mago s que puede utilizar libros de hechizos para luchar. Del mismo

2 de 9

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo5.htm

modo, un mago no puede utilizar armas para pelear. Un mago puede vestir armaduras?. No, los magos slo pueden llevar tnicas de tres colores: negro, rojo o blanco (te suena no?). Adems, en el caso de los guerreros, esto s pueden vestir armaduras pero no tnicas y las armaduras pueden ser de cuero o simplemente nada (el tpico Conan...). Podramos seguir hasta desmenuzar totalmente a cada tipo de personaje pero, con estos datos, ya podemos saber que necesitamos dos clases que heredan de la clase base HUMANO. Estas clases sern la de GUERRERO y la de MAGO. La clase GUERRERO poseer una variable llamada armas cuyo rango de valores podr ir desde espadas a "simples" puos mientras que el MAGO poseer una variable llamada libro de hechizos que trabajar con todos los distintos libros de hechizos que nosotros diseemos. As mismo, la clase GUERRERO dispondr de una variable llamada armadura que tomara los valores de cuero o nada, indicando que no tiene armadura, y la clase MAGO dispondr tambin de una variable similar llamada tnica y su rango ser el de tnica roja, negra o blanca. Y, ahora, el dibujo esquema para aclarar todo. Aconstumbraros a trazar esquemas similares antes de comenzar a codificar. Es muy importante sentar las bases de un diseo, si este va a tener cierta envergadura, pues de lo contrario os veris modificando y ampliando vuestro programa hasta la eternidad. Estis avisados, la metodologa orientada a objetos es as... Ahora os pongo cmo podra ser el esquema grfico (sencillsimo) de lo que aqu se ha tratado de explicar:

Bueno, si no est ms claro que antes si que deberais de apreciar, aunque sea de refiln, lo que trato de mostraros con la jerarqua de clases. Trabajamos con especializaciones o derivaciones sucesivas de clases, vamos a poder utilizar toda la potencia del C++. Ventajas de la utilizacin de clases derivadas. Cualquiera que programe con la metodologa orientada a objetos utiliza la derivacin de clases. Es algo bsico cuando hacemos programas extensos y que requieren de montones de datos para la especializacin. Lgicamente, se puede pasar por alto su aprovechamiento pero entonces, nos limitaramos a programar en C (y rematadamente mal) pero utilizando estructuras y, para eso, slo aprendemos C++ como ampliacin del C y no como metodologa orientada a objetos. La principal importancia de la metodologa orientada a objetos radica en la posibilidad de utilizar el cdigo que otras personas han hecho y trabajar en equipo para llevar a cabo proyectos de gran envergadura. Cuando se programa para entornos como el Windows, por ejemplo, una de las cosas a las que nos tenemos que acostumbrar es a aprender a leer el cdigo que otras personas han hecho ya, a utilizar las clases ya diseadas y codificadas y a adaptarlas a nuestras necesidades. Esto implica crearnos una jerarqua propia a partir de algo que ya est hecho por lo que se torna fundamental el aprender a pensar de esta nueva manera. Si queremos implementar un programa, debemos de ponernos antes delante de un papel y disear a mano los posibles mdulos que vamos a necesitar y, una vez establecidos, desmenuzar esos mdulos en jerarquas de clases. Esto nos va a permitir que, en un futuro, nuestro diseo sea totalmente ampliable y mejorable y que otras personas puedan aprovecharlo para trabajar. Intenta ir ms all del ejemplo anteriormente establecido. Imagina que hay ahora una clase de guerreros distinta que adems tambin son magos. Qu haras?. Crea una clase llamada GUERRERO_MAGO que herede de la clase

3 de 9

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo5.htm

GUERRERO y de la clase MAGO y ya est. Tu personaje ahora podr tener todos los atributos exclusivos de un ser humano, de un guerrero y de un mago. Esto es lo que nos ofrece la herencia y la jerarqua de clases, poder reutilizar cdigo de una forma inteligente. Un ejemplo A continuacin vamos a ver, mediante un sencillo ejemplo, cmo implementar la derivacin de una clase utilizando el concepto de herencia. Utilizaremos, para ello, el modelo ideado ms atrs, es decir, tendremos una clase base llamada HUMANO y de ella se derivarn dos, la clase GUERRERO y la clase MAGO. En la clase HUMANO estarn todos los datos bsicos y que son comunes a los dos tipos de personajes (Guerreros y Magos) mientras que, en la clases ya respectivas, pondremos caractersticas nicas y que les diferencian, como el caso de armas, hechizos, armaduras o tnicas. All vamos!
#include <iostream.h> // Clase Base class Humano { public: // Constructor y destructor Humano(); {} ~Humano(); {} private: // Hago excesivo uso del tipo int porque es un ejemplo // en un caso real, aconstumbraros a utilizar el tipo unsigned char // si vuestros valores no van a rebasar el rango 0-255 char *m_nombre; int m_edad; int m_peso; int m_sexo; int m_inteligencia; int m_fuerza; int m_destreza; int m_energia; public: void PonNombre(char *nombre) { m_nombre = name; } void PonEdad(int edad) { m_edad = edad; } void PonSexo(char sexo) { if (sexo=='V') m_sexo =0; else m_sexo = 1; } void PonInteligencia(int intel) { m_inteligencia = intel; } void PonFuerza(int fuerza) { m_fuerza = fuerza; } void PonDestreza(float destreza) { m_destreza = destreza; } void PonEnergia (int energia) { m_energia = energia; } virtual void PonInformacion(void); }; // Primera clase derivada class Guerrero : public Humano { public: // Constructor y destructor Guerrero() {} ~Guerrero() {} private: int m_tipoArma; // 0 manos 1 espada int m_tipoArmadura; // 0 nada 1 cuero public: void PonArma(int arma) { m_tipoArma = arma; } void PonArmadura(int armadura) { m_tipoAramadura = armadura; } void PonInformacion(void); }; //Segunda clase derivada class Mago: public Humano { public: // Constructor y destructor Mago() {} ~Mago() {} private: int m_tipoLibroHechizos; // 0 ataque 1 curacion int m_tipoTunica; // 0 blanca 1 roja 2 negra public:

4 de 9

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo5.htm

void PonLibroHechizos(int libro) { m_tipoLibroHechizos = libro; } void PonTunica(int tunica) { m_tipoTunica = tunica; } void PonInformacion(void); }; // Ahora implementamos las funciones que no son // inline // Mtodos de la clase Humano void Humano::PonInformacion(void) { cout << "\n Nombre: " << m_nombre; cout << "\n Edad: " << m_edad; switch(m_sexo) { case 0: cout << "\n Sexo: Hombre"; break; case 1: cout << "\n Sexo: Mujer"; break; }; cout << "\n Inteligencia: " << m_inteligencia; cout << "\n Fuerza: " << m_fuerza; cout << "\n Destreza: " << m_destreza; cout << "\n Energa: " << m_energia; } // Mtodos de la clase Guerrero void Guerrero::PonInformacion(void) { Humano::PonInformacion(); switch(m_tipoArma) { case 0: cout << "n Arma: Puos"; break; case 1: cout << "\n Arma: Espada"; break; }; switch(m_tipoArmadura) { case 0: cout << "\n Armadura: Ninguna"; break; case 1: cout << "\n Armadura: Cuero"; break; }; } // Mtodos de la clase Mago void Mago::PonInformacion(void) { Humano::PonInformacion(); switch(m_tipoLibroHechizo) { case 0: cout << "\n Libro: Hechizos de Ataque"; break; case 1: cout << "\n Libro: Hechizos de Curacin"; break; }; switch(m_tipoTunica) { case 0: cout << "\n Tnica: Blanca"; break; case 1: cout << "\n Tnica: Roja"; break; case 2: cout << "\n Tnica: Negra"; break; }; } int main() { // Nota: Pese a que los nombres os sonarn (o, al menos, deberan!) // sus datos los he puesto casi sin mirar... as que los puritanos // de las novelas, disculpen ;-) // Declaramos dos objetos. // Uno de tipo Mago y otro de tipo Guerrero Guerrero Caramon; Mago Raistlin; // Ponemos los datos de cada uno // Datos del guerrero Caramon.PonNombre("Caramon"); Caramon.PonEdad(26); Caramon.PonSexo('V'); Caramon.PonInteligencia(7); Caramon.PonFuerza(8);

5 de 9

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo5.htm

Caramon.PonDestreza(8); Caramon.PonEnergia(100); Caramon.PonArma(1); Caramon.PonArmadura(0); // Datos del Mago Raistlin.PonNombre("Raistlin"); Raistlin.PonEdad(26); Caramon.PonSexo('V'); Raistlin.PonInteligencia(9); Raistlin.PonFuerza(5); Raistlin.PonDestreza(6); Raistlin.PonEnergia(60); Raistlin.PonLibroHechizos(0); Raistlin.PonTunica(1); // Ahora Ponemos los datos del Guerrero por pantalla Caramon.PonInformacion(); // Ahora Ponemos los datos del Mago por pantalla Raistlin.PonInformacion(); return 0; }

Analizando el ejemplo Qu tal lo veis?. Espero que se os hayan aclarado bastantes ms cosas ahora que tenis toda la teora codificada. Como podis observar, utilizamos la clase base HUMANO y, a partir de ella, derivamos las clases GUERRERO y MAGO. Esto da mucha potencia ya que tenemos todo lo bsico en la clase base y creamos clases especficas que se especializan, caso de las citadas GUERRERO y MAGO, ofreciendo esos datos u acciones concretas. Sera muy fcil crear una clase arquero, ladrn, bardo.... tan slo hay que derivar de la clase base y aadir esas caractersticas nicas. A modo de recordatorio, os pongo la clase base HUMANO que establece todas las caractersticas bsicas as como los mtodos para trabajar con ellas. Ah va:
// Clase Base class Humano { public: // Constructor y destructor Humano(); {} ~Humano(); {} private: // Hago excesivo uso del tipo int porque es un ejemplo // en un caso real, aconstumbraros a utilizar el tipo unsigned char // si vuestros valores no van a rebasar el rango 0-255 char *m_nombre; unsigned char m_edad; int m_peso; int m_sexo; int m_inteligencia; int m_fuerza; int m_destreza; int m_energia; public: void PonNombre(char *nombre) { m_nombre = name; } void PonEdad(int edad) { m_edad = edad; } void PonSexo(char sexo) { if (sexo=='V') m_sexo =0; else m_sexo = 1; } void PonInteligencia(int intel) { m_inteligencia = intel; } void PonFuerza(int fuerza) { m_fuerza = fuerza; } void PonDestreza(float destreza) { m_destreza = destreza; } void PonEnergia (int energia) { m_energia = energia; } virtual void PonInformacion(void); };

La clase derivada GUERRERO, hereda todas las funciones o mtodos y todas las variables o atributos de la clase base HUMANO. Adems, aade dos funciones nuevas, dos variables nuevas y redefine una funcin de la clase base, la funcin PonInformacin(). Es decir, la clase GUERRERO es la siguiente:
// Primera clase derivada class Guerrero : public Humano { public: // Constructor y destructor

6 de 9

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo5.htm

Guerrero() {} ~Guerrero() {} private: int m_tipoArma; // 0 manos 1 espada int m_tipoArmadura; // 0 nada 1 cuero public: void PonArma(int arma) { m_tipoArma = arma; } void PonArmadura(int armadura) { m_tipoAramadura = armadura; } void PonInformacion(void); };

Por su parte, la clase MAGO, viene a hacer algo similar. Hereda todas las funciones y variables pblicas de la clase base HUMANO, al igual que la clase GUERRERO y, adems, aade dos variables, dos funciones y redefine la, ya citada, funcin PonInformacion() de la clase base. La clase MAGO es esta:
//Segunda clase derivada class Mago: public Humano { public: // Constructor y destructor Mago() {} ~Mago() {} private: int m_tipoLibroHechizos; // 0 ataque 1 curacion int m_tipoTunica; // 0 blanca 1 roja 2 negra public: void PonLibroHechizos(int libro) { m_tipoLibroHechizos = libro; } void PonTunica(int tunica) { m_tipoTunica = tunica; } void PonInformacion(void); };

Cmo declaramos, exactamente, una clase derivada? Vamos a mirar la cabecera de la clase GUERRERO que nos vale para ilustrar el proceso. Recordemos cmo era:
// Primera clase derivada class Guerrero : public Humano {

Si nos fijamos, despus de poner class Guerrero, ponemos dos puntos ":" y, despus, public Humano. Lo que debemos de hacer es declarar primero el nombre de la clase que, como todos sabemos, es Guerrero, despus los dos puntos ":" y, por ltimo, lo ms importante, debemos de poner el nombre de la clase de la que vamos a derivar o heredar anteponiendo el formato public o private. Estos son los dos nicos especificadores de acceso que podemos poner a la hora de declarar una clase derivada. Con public, heredamos todos los elementos, tanto variables como funciones. Si pusiramos private como especificador de acceso, lo nico que conseguiramos sera hacer oculta una clase derivada del resto del programa pero, como esto no se suele utilizar (nosotros, en principio, no lo vamos a hacer), no se suele indicar, es decir, se suele declarar todo como public a la hora de derivar. Durante la utilizacin de los objetos Guerrero y Mago, utilizamos, mayormente, los mtodos de la clase base, esto es, durante el establecimiento del nombre, edad, sexo, inteligencia, fuerza, destreza o energa, lo que se hace es "echar mano" de los mtodos de la clase Humano y que son heredados. Sin embargo, mtodos como PonArma() o PonTunica(), por poner algn ejemplo, ya pertenecen exclusivamente a los objetos derivados, es decir, estos mtodos no se heredan de ninguna clase. Otro aspecto muy importante es el de la redefinicin de funciones. Cuando redefinimos funciones lo que venimos a hacer es coger una funcin ya hecha, que pertenece a una clase base, y aadirla una serie de caractersticas necesarias para el objeto derivado. Estas caractersticas pueden y suelen, ampliarlas. El ejemplo ms claro es el del mtodo PonInformacion() mtodo que ser el que estudiemos a continuacin. Redefiniendo funciones Retomando el prrafo anterior, el tema de la redefinicin es una valiosa "arma" para poder concretar todo lo que heredamos an ms. As, en nuestros ejemplos, tanto la clase Guerrero como la clase Mago, hacen uso de la redefinicin. Vamos a recordar cmo era la funcin PonInformacion() en la clase base:

7 de 9

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo5.htm

void Humano::PonInformacion(void) { cout << "\n Nombre: " << m_nombre; cout << "\n Edad: " << m_edad; switch(m_sexo) { case 0: cout << "\n Sexo: Hombre"; break; case 1: cout << "\n Sexo: Mujer"; break; }; cout << "\n Inteligencia: " << m_inteligencia; cout << "\n Fuerza: " << m_fuerza; cout << "\n Destreza: " << m_destreza; cout << "\n Energa: " << m_energia; }

Se puede observar perfectamente que lo que hace este mtodo es volcar la informacin concerniente a las variables que contienen (o contendrn) los valores acerca del nombre, edad, sexo, inteligencia, fuerza, destreza y energa del personaje. La pregunta viene ahora. Si un Guerrero o Mago, tiene estos datos, que los hereda y, adems, tiene otros que tambin deber listar, Tendremos que volver a escribir todo otra vez?. La respuesta es NO. Tan slo hace falta mirar a la funcin PonInformacion() de la clase Guerrero o Mago. Echemos un vistazo a la clase Mago y, en concreto, a dicha funcin:
void Mago::PonInformacion(void) { Humano::PonInformacion(); switch(m_tipoLibroHechizo) { case 0: cout << "\n Libro: Hechizos de Ataque"; break; case 1: cout << "\n Libro: Hechizos de Curacin"; break; }; switch(m_tipoTunica) { case 0: cout << "\n Tnica: Blanca"; break; case 1: cout << "\n Tnica: Roja"; break; case 2: cout << "\n Tnica: Negra"; break; }; }

Est ms o menos claro, no?. Lo que hacemos es llamar la funcin definida en la clase base y que se encarga de listar los valores bsicos anteriormente citados. Para ello, ponemos el nombre de la clase base, seguida de los dos puntos de resolucin de mbito y, despus, el nombre de la funcin, es decir, Humano::PonInformacion(); . Una vez hecho esto, definimos la parte de la funcin que nos hace falta y que no es otra que la concerniente al listado de los valores nicos de un Mago, esto es, tipo de libro de hechizos y tipo de tnica, es decir, completamos funcin PonInformacion() para que, adems de listar los datos bsicos sin necesidad de reescribir las instrucciones (llamamos a la funcin definida en la clase base), liste tambin los datos especficos. Esto mismo es aplicable a la clase Guerrero. Y esto es todo por ahora Creo que con este captulo debera de haber quedado claro qu es la herencia y cmo implementarla en nuestros programas en C++. As mismo, debera de comenzar a tomar fuerza el concepto que entraa programar con una metodologa orientada a objetos y es que, hasta que el programador no consigue pensar de esta nueva forma, es muy importante armarse de papel y lpiz y hacer un boceto de lo que debera de ser el diseo. Siempre lo agradeceris cuando os metis, en serio, a codificar. El prximo nmero hablaremos del Polimorfismo y se desvelar esa palabreja de nombre virtual. Hasta que os suene esa palabreja, ya estis en condiciones de ir haciendo cosas algo ms serias. Por qu no intentis hacer un generador de personajes en plan serio?. Basta con disearlo en papel, escribir sus clases, variables y mtodos. Si hacis eso, y lo hacis bien, aprovecharis mucho ms que si os lanzis a codificar como locos. Rercordad que primero hay que saber disear. Luego ya vendr lo de "machacar" el teclado.

[Aula Macedonia] [Curso de POO en C++]

8 de 9

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo5.htm

AULA MACEDONIA a MACEDONIA Magazine

9 de 9

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo6.htm

Curso de Programacin Orientada a Objetos en C++


Artculo realizado por Fernando Rodrguez.

Captulo 6. Funciones virtuales: polimorfismo. En esta ocasin vamos abordar un concepto muy importante de la programacin orientada a objetos: el polimorfismo. Esta caracterstica de la POO, permite que podamos construirnos mtodos para nuestras clase derivadas que parten de una misma clase base, para que adopten comportamientos totalmente distintos. Es un concepto realmente potente y que se lleva a cabo mediante la utilizacin de funciones virtuales. Nosotros ya las hemos utilizado. Si te acuerdas, en el captulo anterior declarbamos la clase que redefinamos como virtual. Hemos utilizado el polimorfismo y sin enterarnos!. Una funcin virtual es un mecanismo que permite a clases derivadas redefinir a las funciones de las clases base. Por tanto, hasta ahora, nos debemos de quedar con que el polimorfismo es una accin que se puede implementar en clases distintas pero que tienen en comn el hecho de heredar de una clase base comn. Dicho mtodo, pese a ser comn para los objetos derivados, es tratado de forma distinta y, por tanto, dando resultados tambin diferentes dependiendo de con qu clase lo invoquemos. Cmo conseguirlo?. Para poder implementar el polimorfismo tenemos las funciones virtuales. Las funciones virtuales se definen en la clase base y son las que sern redefinidas, luego, en las clases derivadas. La declaracin de una funcin virtual se consigue mediante la palabra clave virtual precediendo a la declaracin de la funcin. Por ejemplo: virtual void PonInformacion(void); En este caso, hemos definido una funcin virtual llamada PonInformacion que pertenece a una clase base y que podr ser redefinida, completamente, en una clase derivada para que acte de forma totalmente distinta a cmo lo hace en la clase base. Es muy importante que la funcin de la clase base que vamos a redefinir lleve el identificador virtual pues de lo contrario, la cosa no funcionar como es de esperar. Veremos estos problemas ms adelante. A continuacin vamos a poner un ejemplo en el que, utilizando la funcin de arriba, vamos a ver cmo podemos hacer para que una clase que herede dicha funcin y produzca resultados totalmente distintos a los que se han definido en la clase base para ella. As mismo, utilizamos new y delete para refrescar la memoria (y nunca mejor dicho :-). Recordad que con new y delete podemos crear objetos (o variables) dinmicamente y de forma muy sencilla.
#include <iostream.h> class ClaseBase { // Esta es la clase base. // Definimos una funcin de miembro para la clase base // que adems es virtual e "inline" public:

1 de 4

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo6.htm

vitual void PonInformacion(void) { cout << "\nHola!"; } }; class ClaseDerivada : public ClaseBase { // // // // Hemos definido una clase derivada de la clase ClaseBase. Esta clase, va a utilizar el concepto de polimorfismo redefiniendo por completo la funcin PonInformacion que hereda de la clase ClaseBase. Tambin es "inline".

public: void PonInformacion(void) { cout << "\nAdios!"; } }; int main(void) { ClaseBase *base = new ClaseBase; ClaseDerivada *derivada = new ClaseDerivada; // Ahora llamamos a los mtodos de cada una para observar // que el resultado es distinto. base->PonInformacion(); derivada->PonInformacion(); delete base; delete derivada; return 0; }

Bueno, el resultado est claro, no?. Mientras que la clase declarada como ClaseBase e instanciada con base, pone en pantalla "Hola!", la clase derivada, que ha redefinido la funcin virtual PonInformacion, pone "Adis!". Es un ejemplo, en definitiva, muy sencillo en el que se puede ver cmo hacer que una funcin ya definida en una clase base cambie totalmente segn nuestras necesidades: es el polimorfismo. Otra de las cosas que vimos en el captulo anterior era el hecho de utilizar dentro de la funcin de la clase derivada, a la funcin virtual de la clase base. Si nosotros hubiramos implementado as a la funcin virtual de la clase derivada:
void PonInformacion(void) { // Suponemos que la declaracin es inline ya que si no fuera // inline deberamos de poner // void ClaseDerivada::PonInformacion(void) ClaseBase::PonInformacion(); cout << "\nAdios!"; }

Cuando llamramos a la funcin PonInformacion() por medio de la clase derivada, esto es, cuando hiciramos:
derivada->PonInformacion();

Lo que nos saldra por pantalla sera: Hola! Adios! En contraposicin a lo que nos sale en el programa original en el que no llamamos a la funcin de la clase base, es decir, en el ejemplo original saldra nada ms Adis!. Esto es as porque dentro del cuerpo PonInformacion() que est implementado en la clase ClaseDerivada, llamamos antes de nada a la funcin de la clase base ClaseBase que se trata como una funcin heredada ms. Aclarando todo un poco Si recuerdas el captulo anterior del curso, habrs observado que, en cierta forma, ya hemos utilizado el polimorfismo, es decir, en el anterior captulo redefinamos funciones miembro de una clase base utilizando sus caractersticas comunes a la clase derivada en la que trabajbamos pero aadiendo una serie de especificaciones extra para que "adems se hiciera otra cosa".

2 de 4

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo6.htm

Hasta ahora hemos tratado funciones que son virtuales simples. Recordemos que una funcin virtual es aquella que, habindose declarado en una clase base, vuelve a declararse y a implementarse en una clase derivada, es decir, se redefine en la clase derivada. De esta forma, cuando el objeto instanciado a una clase derivada, llama a esa funcin virtual, lo que se hace es llamar a la funcin de la clase derivada no a la funcin de la clase base (a no ser que, dentro de la funcin de la clase derivada, se llame a la funcin de la clase base). El ejemplo clsico de utilizacin de funciones virtuales est en el de crear una clase base llamada Forma con una funcin de miembro para dibujar y de nombre Dibujar. Si nosotros creamos dos clases derivadas de la clase base Forma llamadas Circulo y Rectangulo, respectivamente, y redefinimos la funcin virtual Dibujar en cada una de las clases base, cuando la llamemos desde cada una de las instancias a la funcin Dibujar, el compilador sabr a qu funcin llamar.

Cabe decir tambin, y esto es importante pues puede dar lugar a confusiones, que si tenemos una funcin en una clase base que no est marcada como virtual y despus creamos en una clase derivada otra funcin con el mismo nombre los resultados no van a ser los esperados... Lo que har el compilador ser llamar directamente a la funcin implementada en la clase base y pasar "olmpicamente" de la implementacin de la clase derivada. y si, habiendo declarado una funcin en la clase base como virtual, luego se nos olvida redefinirla en la clase derivada?. Bueno, en este caso, se llamar a la funcin de la clase base y no pasar nada. Funciones virtuales puras implican clases abstractas. Se puede decir que las funciones virtuales puras son aquellas que, para implementarse, han de ser redefinidas, es decir, que no slo tienen sino que deben ser redefinidas. Aquellas clases que tengan una funcin virtual pura se denominan clases abstractas y tienen la gran particularidad de que de ellas no se puede crear instancias u objetos. Quedamos, pues, en que para crear una clase abstracta slo hace falta definir una funcin virtual pura. Y cmo definimos una funcin virtual pura?. Para definir una funcin virtual pura, tenemos que asignar a la funcin un puntero NULL o, lo que es lo mismo, un valor 0. Suponiendo que queremos implementar una funcin llamada Forma como virtual pura, deberamos de poner as:
virtual void Forma() = 0;

La clase que contenga una sola funcin virtual pura pasa a ser una clase abstracta independientemente de que el resto de sus funciones no sean virtuales puras. Ya veis que fcil es crear una funcin virtual pura y que poder tienen al implicar tambin la creacin de una clase abstracta que, recordad, no puede ser nunca instanciada. Las funciones virtuales puras han de ser definidas cuando queramos crear una verdadera clase raz de una serie de clases derivadas ciertamente importante. No conviene abusar de esta caracterstica del C++ a no ser que vuestro diseo lo necesite necesariamente y estis delante de un proyecto con una complejidad notable.

3 de 4

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo6.htm

Conclusiones finales Decir, finalmente, que las funciones virtuales se caracterizan por aadir una mayor cantidad e trabajo computacional y que, por tanto, es recomendable utilizar las prestaciones del polimorfismo, esto es, poner la palabra clave virtual a una funcin, slo cuando estemos seguros de que esa funcin va a ser redefinida. Tampoco es que se consuma mucho tiempo y se sobrecargue todo en exceso pero suele ser una prctica comn entre los que comienzan a trabajar ms o menos en serio con el C++ utilizar prestaciones de la POO cuando no son necesarias. Si cuando lleves un tiempo codificando descubres que la funcin declarada como virtual no va a ser redefinida quita la palabra clave virtual de la funcin de miembro de la clase base.

[Aula Macedonia] [Curso de POO en C++]

AULA MACEDONIA a MACEDONIA Magazine

4 de 4

30/01/2012 11:02 a.m.

http://macedoniamagazine.frodrig.com/poo7.htm

Curso de Programacin Orientada a Objetos en C++


Artculo realizado por Fernando Rodrguez.

Captulo 7. Sobrecargando funciones y operadores. La sobrecarga es uno de los mecanismos ms utilizados del C++ pues reporta una gran cantidad de beneficios a la hora de disear las prestaciones de nuestras funciones de miembro. Existen dos tipos fundamentales de sobrecarga: la sobrecarga de funciones y la sobrecarga de operadores. Sobrecarga de funciones La sobrecarga de funciones consiste, bsicamente, en crear funciones con el mismo nombre dentro de una clase pero con distinto tipo de argumentos de tal forma que, al llamar a la funcin el compilador se encargar de escoger la adecuada mediante la comparacin de la lista de argumentos pasados en la invocacin. Un sencillo ejemplo sera pensar en dos funciones llamadas ImprimirMensaje Podemos definirlas as:
void ImprimirMensaje(void); void ImprimirMensaje (char *texto);

Como podis observar, se llaman igual pero tienen argumentos distintos. Mientras que la primera no est preparada para recibir ningn tipo de datos, la segunda s que lo est y esperar recibir una cadena de caracteres. Si ahora implementamos las funciones de esta forma:
void NombreClase::ImprimirMensaje(void) { cout << "\n Esta es la funcin sin argumentos"; } void NombreClase::ImprimeMensaje(char *texto) { cout << "\ n Esta es la funcin con argumentos y ha recibido el mensaje " << texto; }

Si creramos una instancia a la clase que contiene a esas dos funciones y llamramos a la funcin
ImprimeMensaje();

Obtendramos por pantalla:


Esta es la funcin sin argumentos

Si, con esa misma instancia, llamramos a la funcin


ImprimeMensaje("Macedonia Magazine");

Lo que obtendramos sera:


Esta es la funcin con argumentos y ha recibido el mensaje Macedonia Magazine

1 de 3

30/01/2012 11:03 a.m.

http://macedoniamagazine.frodrig.com/poo7.htm

Como podis observar, es muy sencillo sobrecargar funciones (ms que sobrecargar operadores) y pueden ofrecer, sin un coste computacional demasiado elevado, prestaciones excelentes para trabajar dada la gran flexibilidad que proporcionan al programador. He aqu el ejemplo codificado formalmente:
#include <iostream.h> class SobrecargaFunciones { public: void ImprimeMensaje(void); void Imprime Mensaje(char* texto); }; void SobrecargaFunciones::ImprimirMensaje(void) { cout << "\n Esta es la funcin sin argumentos"; } void SobrecargaFunciones::ImprimeMensaje(char *texto) { cout << "\n Esta es la funcin con argumentos y ha recibido el mensaje " << texto; } int main(void) { SobrecargaFunciones sobrecarga; sobrecarga.ImprimeMensaje(); sobrecargaImprimeMensaje("Macedonia Magazine"); }

Sobrecarga y constructores La sobrecarga de constructores se presenta como una de las aplicaciones ms directas y comunes de aplicacin de este mecanismo del C++, es ms, la sobrecarga de constructores es algo que est "a la orden del da" para cualquier programador de C++ pues permite inicializar las instancias de muy distintas formas y dotar al objeto de unos valores iniciales acordes a la finalidad a la que vamos a llevar dicho objeto. Es muy comn, pues, ver clases con muchos constructores. Por ejemplo:
class Personaje { public: Personaje(char *nombre); Personaje(); }

Aqu, podramos decidir inicializar a la instancia con un nombre que el usuario ha introducido por teclado o bien, crear nosotros la instancia Personaje con un nombre por defecto llamando al constructor sin ningn tipo de argumentos. Sobrecarga de operadores La sobrecarga de operadores no es un mecanismo que los programadores de C++ recin iniciados se aventuren a utilizar ya que tardan un tiempo en "pillarle el truco" pero es masivamente utilizado en cualquier biblioteca de C++ como la MFC de Microsoft. Pero, en qu consiste una sobrecarga de operadores?. Sobrecargar operadores sirve para que las operaciones tales como la suma (+), resta (-), multiplicacin (*), asignacin (=), incremento (--), etc se comporten de forma diferente al trabajar con nuestros objetos, ms exactamente, con los objetos preparados para soportar la sobrecarga de operadores. Imaginar que tenemos dos objetos de tipo Cadena. La clase Cadena est preparada para manejar una cadena de caracteres y darla funcionalidad a travs de diversos mtodos. Si nosotros quisiramos sumar dos objetos de tipo Cadena, bastara con tener sobrecargado el operador suma (+) para los objetos de dicha clase con lo que la siguiente sentencia sera vlida:
Cadena cadena1, cadena2, cadenaResult; cadenaResult = cadena1 + cadena2;

Con esto podramos conseguir, por ejemplo, que el objeto cadenaResult almacenara la concatenacin de las cadenas de caracteres que soportan los objetos cadena1 y cadena2 respectivamente.

2 de 3

30/01/2012 11:03 a.m.

http://macedoniamagazine.frodrig.com/poo7.htm

Cmo implementar la sobrecarga de operadores Para sobrecargar un operador, debemos de definir una funcin de sobrecarga de operador en la clase que nos interese (aunque tambin la podemos hacer de carcter global... y eso podra traer algn que otro "galimatas" si no tenis cuidado). Un operador que se sobrecarga se define siempre con el nombre de la clase seguido de la palabra clave operator y del operador. Despus del operador pondremos, entre parntesis, los tipos de datos con los que queremos que funcione nuestro operador. Por ejemplo, si quisiramos sobrecargar el operador suma de la clase Cadena, deberamos de incluir, en la definicin de la clase, la siguiente definicin:
Cadena operator+(Cadena);

Con esto estaramos declarando que estamos sobrecargando el operador suma (+) para que sea capaz de trabajar con argumentos (sumandos) que sean instancias a la clase cadena. Obviamente, para que esto funcione en la parte izquierda del operador asignacin debe de haber otro objeto de tipo de Cadena, es decir, no podemos hacer esto:
int valor; valor = cadena1 + cadena2;

Recordemos que estamos sobrecargando el operador suma para que trabaje con objetos que sean instancias de la clase Cadena. Prximo captulo Los dos ltimos captulos que hemos visto sobre polimorfismo y sobrecarga nos ponen en condiciones de comenzar la recta final de este curso. El siguiente captulo estar dedicado a las variables de miembro y funciones de miembro estticas as como a las clases y funciones amigas por lo que volvern los largos captulos y dejaremos casi acabado el curso. Hasta entonces feliz programacin!.

[Aula Macedonia] [Curso de POO en C++]

AULA MACEDONIA a MACEDONIA Magazine

3 de 3

30/01/2012 11:03 a.m.

http://macedoniamagazine.frodrig.com/poo8.htm

Curso de Programacin Orientada a Objetos en C++


Artculo realizado por Fernando Rodrguez.

Captulo 8. Variables y funciones de miembro estticas.


En este captulo abordaremos el estudio de las variables y funciones de miembro estticas. Veremos cmo podemos aprovechar su potencia para ir olvidndonos, poco a poco, de todo lo concerniente al uso de variables globales. Este tipo de variables se caracterizan, pues, por ofrecernos una serie de servicios comunes a los que las variables globales nos han brindado siempre en el C tradicional pero aportando una mayor seguridad. Con las funciones de miembro estticas veremos cmo acceder a ese tipo de variables de forma exclusiva. Variables de miembro estticas. De todos es conocido los numerosos problemas que traen las variables globales en el momento en que acometemos un proyecto de dimensiones moderadamente serias. Enseguida empezamos a tener dudas si la variable que estamos tratando es global o no, empezamos a cambiar los valores inadvertidamente desde las funciones y, en consecuencia, empiezan a producirse fallos totalmente inesperados que terminan por hacer que reescribamos un buen montn de cdigo que realmente no haca falta revisar. En la programacin en C tradicional, seguro que alguna vez habis tenido que utilizar variables globales para poder saber en cualquier momento o en cualquier funcin, la situacin del programa. Pues bien, en el C++ las variables de miembro estticas suponen una alternativa seria y eficaz al uso de las variables globales. Cuando declaramos una variable de miembro esttica en una clase, todos los objetos que sean instancia de esa clase, usarn la misma variable de miembro esttica. Por tanto, una variable de miembro esttica declarada en una clase, utilizar siempre una misma posicin de memoria independientemente del nmero de instancias que creemos a esa clase, es decir, si la clase que contiene la variable de miembro esttica tiene cien instancias, los cambios que efectuemos en la variable de miembro esttica desde la instancia nmero 45, har que el resto de instancias tambin contengan ese valor. Uno de los usos ms comunes de las variables de miembro estticas son los derivados de contabilizar el nmero de instancias que tiene una clase. Si declaramos una variable de miembro esttica en una clase con el nombre m_numInstancias y desde el constructor hacemos m_numinstancias++; y desde el destructor hacemos m_numInstnacias--; nos ser posible conocer el nmero de instancias existentes desde cualquier objeto creado. Este es un buen ejemplo de comprender todo lo que se ha dicho anteriormente y lo mostrar al final de la seccin correspondiente a variables estticas. Cmo crear una variable de miembro esttica Para declarar una variable de miembro esttica lo nico que debemos de hacer es anteponer la palabra clave static a la definicin de tipo, es decir, si queremos declarar una variable de miembro esttica de tipo entero con el nombre m_staticValor, haramos lo siguiente:
static int m_staticValor;

Con esta simple declaracin hemos creado una variable de miembro esttica. A partir de este momento, m_staticValor slo ocupar una posicin de memoria. Independientemente del nmero de instancias que se creen de la clase que la define. Slo existir una posicin de memoria de tal forma que realizar un cambio en el valor de m_staticValor se ver

1 de 5

30/01/2012 11:03 a.m.

http://macedoniamagazine.frodrig.com/poo8.htm

reflejado en todas las instancias de la clase que defina a m_staticValor. En este sentido, podemos observar que una variable de tipo esttico tiene las mismas prestaciones que una variable de tipo global. A la hora de acceder a una variable de miembro esttica, primero debemos de tener en cuenta cmo se ha declarado la variable, es decir, si es pblica, protegida o privada. Una variable de miembro esttica pues, se puede acceder perfectamente desde dentro de las funciones de la clase que la definen. Tambin se puede acceder utilizando el operador "." o "->" en caso de que la instancia que se haya creado sea un puntero. Ase, si la clase con el nombre CEjemplo contiene una definicin de la variable esttica m_staticValor, podramos hacer (siempre y cuando, la variable m_staticValor fuera pblica, claro), lo siguiente:
CEjemplo prueba; // Instancia a CEjemplo. // Accedemos a m_staticValor porque es pblica prueba.m_staticValor = 20;

Un caso a parte lo constituyen las funciones que no pertenecen a la clase que define la variable de miembro esttica. En estos caso, hemos de acceder al valor esttico utilizando el operador de resolucin de mbito "::". Es decir, si quisieramos acceder a m_staticValor desde la funcin main del programa, deberamos de hacer CEjemplo::m_staticValor = 20 De nuevo, para que esto funcione, la variable esttica m_staticValor ha de ser declarada como pblica. En lneas generales, y sin despreciar estos ejemplos anteriormente mostrados, lo ideal es crearnos variables estticas de tipo privado y, mediante el uso de funciones estticas de tipo pblico, hacer las manipulaciones pertinentes a estas poderosas variables. Las funciones estticas, que veremos ms adelante, se caracterizan, entre otras cosas, por trabajar nicamente con variables estticas. Un ejemplo con declaracin y definicin de variables estticas Vamos a poner ahora un ejemplo de todo las formas de acceso que hemos comentado ms arriba. Vamos a ver cmo acceder a una variable de miembro esttica pblica mediante el operador de resolucin de mbito, mediante el operador ".", y, cmo no, mediante la utilizacin de una funcin. Crearemos dos objetos de tal forma que se compruebe cmo el cambio de valor en la variable en uno de los objetos se ve reflejado tambin en el otro. El ejemplo es muy sencillo.
#include <iostream.h> // Ejemplo de cmo utilizar variables de miembro // estticas. class CEjemplo{ // Variables pblicas public: // Declaracin de la variable esttica static int m_staticValor; // Funciones pblicas public: CEjemplo(){} // Constructor ~CEjemplo() {} // Destructor void PonValor(int valor) { m_staticValor = valor; } int MuestraValor() { return m_staticValor; } }; // Definicin de la variable esttica int CEjemplo::m_staticValor; void main(void) { CEjemplo objeto1; // Instancia 1 CEjemplo* objeto2 = new CEjemplo; // Instancia 2 objeto1.m_staticValor = 10; cout << "\n el valor es: " << objeto1.m_staticValor; objeto2->PonValor(20); cout << "\n el valor es: " << objeto1.MuestraValor(); CEjemplo::m_staticValor = 30; cout << "\n el valor es: " << objeto1.MuestraValor() << " y es igual a: " << objeto2->m_staticValor << "\n\n\n"; cin; }

2 de 5

30/01/2012 11:03 a.m.

http://macedoniamagazine.frodrig.com/poo8.htm

Lo primero que hacemos es declarar la variable de miembro esttica tal y como habamos visto al principio de este captulo, dentro de la clase, esto es:
// Variables pblicas public: // Declaracin de la variable esttica static int m_staticValor;

Despus definimos los constructores, destructores y funciones de miembro pblicas para trabajar con esa variable:
// Funciones pblicas public: CEjemplo(){} // Constructor ~CEjemplo() {} // Destructor void PonValor(int valor) { m_staticValor = valor; } int MuestraValor() { return m_staticValor; }

A continuacin, viene una parte muy importante, pues hemos de definir la variable de miembro esttica que hemos declarado dentro de la clase. Esto es as por el tema de que una variable de miembro esttica es compartida por mltiples funciones. Por tanto, recordad que una variable de miembro esttica debe de declararse dentro de la definicin de una clase y despus, debe de definirse fuera de la definicin de la clase. En caso de no hacer esto, el compilador os mostrar errores. Aqu tenis la definicin fuera de la clase:
// Definicin de la variable esttica int CEjemplo::m_staticValor;

Ahora todo es mucho ms fcil, nos limitamos a "jugar" con los posibles accesos que podemos hacer a la variable y, despus, mostramos el valor por pantalla. Este es el resultado:

Ultimos apuntes sobre las variables estticas Antes de dejar el estudio de las variables estticas, recordar que si estamos trabajando con variables estticas privadas no podemos acceder "al libre albedrio" tal y como hemos hecho antes. Al declarar una variable esttica privada, slo podremos acceder mediante funciones, nunca directamente, es decir, aplicamos todos nuestros conocimientos ya adquiridos de acceso pblico, protegido y privado. Recodar tambin que es absolutamente necesario seguir la regla de declarar dentro de la definicin de la clase y definir fuera de la definicin de la clase, la variable de miembro esttica. Valga este ltimo ejemplo, para mostrar una forma de contabilizar el nmero de instancias a una misma clase.
#include <iostream.h> // Este ejemplo muestra cmo poder llevar // la cuenta del nmero de instancias a una // clase

3 de 5

30/01/2012 11:03 a.m.

http://macedoniamagazine.frodrig.com/poo8.htm

class CEjemplo2{ // Variables private: // Declaramos la variable esttica static unsigned int m_contInstancias; // Funciones public: CEjemplo2() { m_contInstancias++; } ~CEjemplo2() { m_contInstancias--; } unsigned int NumInstancias() { return m_contInstancias; } }; // Definimos la variable esttica // y aprovechamos para inicializarla unsigned int CEjemplo2::m_contInstancias = 0; void main (void) { CEjemplo2 objeto1, objeto2; CEjemplo2* objeto3 = new CEjemplo2; cout << "\nExisten " << objeto1.NumInstancias() << " instancias a la clase CEjemplo2"; cout << "\n"; delete objeto3; cout << "\nBorramos una instancia y ahora existen " << objeto2.NumInstancias() << " instancias a la clase CEjemplo2 \n\n\n"; cin; }

La salida de este ejemplo es:

Funciones de miembro estticas Las funciones de miembro estticas se caracterizan porque slo trabajan con funciones de miembro estticas. Al contrario que una funcin de miembro "convencional" (esto es, una funcin de miembro como las que hemos visto hasta ahora), una funcin de tipo esttica slo podr trabajar, como ya he dicho, con las variables anteriormente explicadas. Para declarar una funcin de miembro esttica es necesario anteponer la palabra clave static antes de definir qu es lo que devuelve la funcin de miembro. As, si quisiramos declarar como funcin de miembro esttica la funcin de miembro NumInstancias del ltimo ejemplo (cosa, por otra parte, totalmente recomendable), la definicin de la clase debera de tener el aspecto siguiente:
class CEjemplo2{ // Variables private:

4 de 5

30/01/2012 11:03 a.m.

http://macedoniamagazine.frodrig.com/poo8.htm

// Declaramos la variable esttica static unsigned int m_contInstancias; // Funciones public: CEjemplo2() { m_contInstancias++; } ~CEjemplo2() { m_contInstancias--; } // Ahora la funcin NumInstancias es esttica. static unsigned int NumInstancias() { return m_contInstancias; } };

Fijaros en la funcin NumInstancias que ahora lleva la palabra clave static:


// Ahora la funcin NumInstancias es esttica. static unsigned int NumInstancias() { return m_contInstancias; }

Lo que puede y no puede hacer una funcin esttica Una funcin de miembro esttica no puede acceder a variables que no son estticas, es decir, si tuviramos definido en la clase CEjemplo2 una variable del tipo:
int m_x;

La funcin esttica NumInstancias NO podra acceder a la variable m_x. Cuidado con esto porque si no lo sabis podis morir de la manera ms tonta dando cabezazos a vuestro monitor ;). Como recordaris, el puntero this es un parmetro que se pasa "en secreto" a todas las funciones que pertenecen a una clase. Con el puntero this podemos acceder a todos y cada uno de los miembro de esa clase. Pues bien, en las funciones de miembro estticas no se pasa el puntero this as que no podris utilizar este valioso puntero para acceder a otros miembros desde la funcin del ejemplo NumInstancias. Prximo captulo En el prximo captulo, abordaremos las clases y funciones amigas "friends", que permitir establecer lazos de unin o, mejor dicho, comunicacin a distintos niveles entre distintas clases y distintas funciones.

[Aula Macedonia] [Curso de POO en C++]

AULA MACEDONIA a MACEDONIA Magazine

5 de 5

30/01/2012 11:03 a.m.

http://macedoniamagazine.frodrig.com/poo9.htm

Curso de Programacin Orientada a Objetos en C++


Artculo realizado por Fernando Rodrguez.

Captulo 9. Gestin de memoria; los operadores new y delete. En este penltimo captulo del curso vamos a hablar de los operadores destinados a la gestin de memoria. Todos recordamos, como programadores de C, que en este lenguaje tenamos instrucciones como malloc o free, entre otras, para reservar espacio a datos en tiempo de ejecucin. El gran problema de estas instrucciones, adems de su moderada complejidad, consista en que eran funciones, es decir, era necesario incluir el consabido archivo de cabecera, que haca aumentar, de forma considerable, el tamao final del ejecutable. Con el C++ tenemos dos excelentes operadores para la gestin de memoria: new y delete. Gracias a la incorporacin de estos operadores, en C++, no va a ser necesario definir ningn archivo de cabecera extra, es decir, new y delete son operadores no funciones con lo que van incluidos en el propio lenguaje C++. Adems de esta innegable ventaja, new y delete no son tan "estrictos" como malloc y free pues permiten usarse sin tener que recurrir a una ahormado de tipos, es decir, no tenemos que convertir un puntero de tipo void (que era el puntero devuelto por malloc) al puntero que nos interesa. El operador new devuelve un puntero que es el que exactamente estbamos persiguiendo. Un poco de teora sobre memoria Durante los ejemplos de los ltimos captulos del curso hemos estado utilizando, de vez en cuando, estos operadores para crear punteros a objetos (aunque tambin podramos haberlos utilizado para crear cualquier otro tipo de variables). Las variables de tipo dinmico creadas por el operador new y eliminadas con el operador delete, se almacenan en una porcin de memoria llamada heap (o montn). Las variables locales a una funcin, es decir, las que se definen en tiempo de compilacin, junto a los argumentos que sta recibe se almacenan en una porcin de memoria llamada pila (o stack). La memoria heap es capaz de dar "cobijo" a estructuras de datos muy grandes ya que su espacio depende de la cantidad de memoria virtual que tengamos en el sistema propio. Es por esto que se utilicen siempre para alojar grandes estructuras como arrays u instancias a clases de gran tamao. El principal problema en este tipo de memoria es que nosotros, como programadores, debemos de hacernos cargo de "limpiar" la memoria al abandonar el programa ya que de lo contrario, nuestras variables dinmicas seguirn estando ah y podrn producir serios fallos en el sistema al intentar arrancar otros programas. La memoria de pila, por el contrario, es de mucho menor tamao. Esta memoria es reservada en tiempo de compilacin y no es capaz de variar; siempre tiene el mismo tamao. En esta memoria se alojan las variables locales a una funcin y los propios argumentos que esta recibe. Las variables declaradas localmente a una funcin se caracterizan por no tener que necesitar un seguimiento tan "exhaustivo" como las de tipo dinmico. Esto hace que su utilizacin sea muy sencilla pues el compilador se encarga de borrarlas y de gestionar la memoria por nosotros en el momento en que nuestro programa en ejecucin, abandona la funcin en cuestin. Suele ser comn que cuando no se tiene cuidado a la hora de declarar las variables en la pila se produzcan "stack's overflows" (pila desbordada) en tiempo de ejecucin.

1 de 3

30/01/2012 11:05 a.m.

http://macedoniamagazine.frodrig.com/poo9.htm

La principal diferencia, pues, entre el heap y la pila es que la pila es una porcin de memoria de tipo esttico, es decir, hay un lmite que no se puede sobrepasar, mientras que la memoria heap es dinmica, es decir, vara en funcin de la que necesitemos en cada momento y con los compiladores de 32 bits, esta memoria tiene una capacidad enorme que es directamente proporcional a la memoria virtual libre en el equipo del usuario. Por memoria virtual se entiende toda la memoria del sistema, tanto la ram libre como la del disco duro (que tambin se puede utilizar como memoria para "alocatear" los programas o procesos). El operador new El operador new viene a hacer las veces de la funcin malloc del C tradicional. Con la funcin malloc, nosotros podamos reservar memoria en tiempo de ejecucin. El principal problema es que siempre debamos de especificar el tipo de puntero que queramos que se nos devolviera pues esta funcin retornaba el puntero genrico void, esto es, era una funcin algo ms compleja de lo habitual. He aqu un ejemplo con la vieja malloc:
// Ejemplo que reserva memoria para 1000 enteros, es decir, // se reservan 1000x2bytes de un int = 2000 bytes. int *m_buffEnteros; m_buffEnteros = (int *) malloc(1000);

Como se comentaba ms atrs, el uso de operador new es mucho ms sencillo. Para reservar toda esa buffer, slo deberamos de hacer esto:
int* m_buffEnteros; m_buffEnteros = new int[1000];

o de forma ms clara y usual


int* m_buffEnteros = new int[1000];

En estos dos ejemplos de uso de malloc y new hemos declarado un puntero llamado m_buffEnteros que apunta a una zona de memoria reservada para 1000 enteros y que tiene un tamao de 2000 bytes. En el caso de que no existiera memoria disponible en el sistema, el operador new devolvera un valor igual a 0. Por otro lado, como el operador new hace una comprobacin de tipos, si el puntero no es del tipo correcto se lanza un mensaje de error. As, si queris ser previsores se recomendara hacer algo as:
int* m_buffEnteros = new int[1000] ; if (m_buffEnteros) cout << "\nSe ha reservado memoria!"; else cout << "\nError: No se ha reservado memoria!";

De todos modos, es muy raro que no exista memoria disponible (pero s posible), sobretodo si estis trabajando con un compilador de 32 bits como puede ser el Visual C++, ltimas versiones, con lo que esa comprobacin quizs resulte excesivamente preventiva. El operador delete El operador delete sirve para liberar la memoria que hayamos reservado con el operador new. Es realmente similar al free. El nico inconveniente que podra ocasionar el uso del operador delete sera el utilizarlo en aquellos casos en el que el puntero a borrar realmente no ha sido reservado correctamente con la llamada a new y tiene un valor no nulo. En los dems casos, esto es, cuando el puntero valga NULL o realmente apunte a una zona de memoria que s ha sido correctamente reservada. La forma de utilizar el operador delete es muy sencilla, basta con poner delete y seguidamente el puntero:
delete m_buffEnteros;

De la misma forma que se escribi la forma de ser precavidos con el uso de new, pongo a continuacin una forma

2 de 3

30/01/2012 11:05 a.m.

http://macedoniamagazine.frodrig.com/poo9.htm

elegante para utilizar delete:


if (m_buffEnteros) { delete m_buffEnteros m_buffEnteros = NULL; }

Para terminar Utilizad new y delete pues facilitan un montn el trabajo con memoria y realmente todo son ventajas. Ni que decir tiene que el trabajo de los punteros que se han reservado con estos operadores es el de siempre, es decir, si estis trabajando con variables hay que utilizar el operador uniario "*" para acceder al valor. Si trabajis con estructuras o instancias, esto es, objetos, deberis de utilizar el operador "->" para acceder a los miembros. Si revisis ejemplos de captulos anteriores veris casos de estos. De todas formas, cuidado con la memoria ;). Y ahora qu? Realmente ya se han redactado todos los captulos del curso de programacin orientada a objetos con C++ que si recordis fue establecido en el captulo 1. De todas formas, se har un captulo ms en el que se abordar un caso muy prctico y de vigente actualidad: "Las MFC y el Visual C++". Por tanto, hasta el prximo y ltimo!.

[Aula Macedonia] [Curso de POO en C++]

AULA MACEDONIA a MACEDONIA Magazine

3 de 3

30/01/2012 11:05 a.m.

http://macedoniamagazine.frodrig.com/poo10.htm

Curso de Programacin Orientada a Objetos en C++


Artculo realizado por Fernando Rodrguez.

Captulo 10. Y para concluir, una mencin a las MFC. Con este captulo se da por finalizado el curso concerniente a la programacin orientada a objetos mediante el uso del C++. Naturalmente, no se ha hablado de todos los temas de la POO pero s de los ms importantes (los que la mayora de programadores suelen utilizar). Realmente es muy difcil que un desarrollador de C++ utilice todos los mecanismos que la programacin orientada a objetos le brinda ya que, o bien no es necesario para su proyecto o bien... lo desconoce. Es muy complicado tener un conocimiento total de todo lo que nos ofrece el C++. En este ltimo captulo, me gustara hablar un poco de la librera de clases MFC (Microsoft Fundation Classes) que, como sabris, son las utilizadas en la programacin en Visual C++ (siempre y cuando no acudas al API mediante la programacin directa, en C tradicional, o mediante la construccin de tus propias clases). Las MFC son una gran desconocida para muchos de los programadores de Windows ya que han tardado en "digerirse" ms de lo esperado. Principalmente porque lo que siempre ha estado "ah" ha sido el API y la totalidad de programadores de Windows que venan de trabajar en la versin de 16 bits lo hacan con el API. Si a esto unimos la elevada complejidad (para qu nos vamos a engaar) que entraa enfrentarte por vez primera a esta librera de clases de Microsoft, pues veremos que la criba de programadores preparados para su utilizacin es mucho ms escasa que la referente a usuarios del API. De todas formas, los hbitos de programacin en Windows (bajo C), estn cambiando y ya hay un movimiento destinado al uso de las MFC. Desde los programadores aficionados a la creacin de videojuegos (que siempre han criticado, no sin razn, de la lentitud de estas clases para la programacin de juegos rpidos), hasta, cmo no, desarrolladores de aplicaciones. Este ltimo hecho, tambin ha producido disparidad de opiniones. No hay ms que leer los artculos de mi colega Jos Antonio en el que se ponen de manifiesto "lo poco visual que es el Visual C++". Ciertamente, programar en Visual C++ utilizando las MFC, no es tan directo como hacerlo en Delphi o Visual Basic. En MFC hay que escribir ms cdigo y bajar a la "sala de mquinas" de forma reiterada. Este importante sacrificio que entraa el utilizar el Visual C++ como herramienta para desarrollar aplicaciones bajo Windows usando las MFC, tiene un premio que es la infinita potencia que ofrece al programador (al que est dispuesto, claro, a utilizar una completa bibliografa).

Entrando en materia...
Todo programador de Windows que utilice el API siempre se sorprende de no encontrar por ningn lado la funcin WinMain tradicional en los listados que utilizan MFC. La programacin en MFC se caracteriza por encapsular casi todas (no estn todas) las llamadas que existen en el API, en una serie de clases que estn englobadas segn el tipo de cometido. Lgicamente, hay muchsimas clases ya que el API de Windows es, desgraciadamente, muy enrevesado. Pero, precisamente por eso, el uso de clases que encapsula toda esa cantidad ingente de llamadas que existen (es como si te las catalogaran), se hace muy de agradecer. Como se ha dejado entrever, no todas las llamadas al API estn encapsuladas en la biblioteca de clases que son las MFC. Hay algunas que no se encuentran. Sin embargo, no hay por qu preocuparse ya que podemos acceder fcilmente a las mismas mediante llamadas directas al API. As, todos los programadores tradicionales del API de Windows pueden utilizar llamadas a la misma mezcladas con cdigo

1 de 4

30/01/2012 11:08 a.m.

http://macedoniamagazine.frodrig.com/poo10.htm

en MFC. Programar en MFC no es nada sencillo. Si se ha trabajado en C++ se puede leer cdigo en C sin ningn tipo de problema sin embargo, esto ya no sucede a la inversa. Conocerse "al dedillo" el C no significa que uno pueda sentirse cmodo examinando un listado escrito en C++ y bueno... las MFC son C++ bastante puro y duro (y muy, MUY, enrevesado). La curva de aprendizaje es bastante elevada. yo me atrevera a decir que ms, mucho ms, que la que conlleva aprender a moverse en Windows con el API. De todas formas, a la larga merece la pena. Mientras aprendes MFC puedes ir aprendiendo el API pero mientras aprendes el API no puedes ir aprendiendo MFC. Una de las principales ventajas y, a la vez, inconvenientes del uso de las MFC, es que debemos estar preparados para leer y entender una buena cantidad de cdigo que no ha sido escrito por nosotros. Eso es malo?. Hombre, al principio s porque te encuentras muy perdido entre la ingente cantidad de cdigo que se te muestra delante de tus narices. Recuerdo que la primera sesin en mi aprendizaje de MFC fue de autntico terror. Tena unos cuantos archivos .CPP recin creados. Montones de comentarios, clases, mtodos... Cmo hacer "algo" sin volverme loco?. El hecho de conocer el API ayuda bastante porque, al menos, te da una cierta seguridad de cara a la investigacin sobre el funcionamiento de todo el cdigo que se te presenta pero, sinceramente, si nunca se ha programado en C++, el uso de las MFC es un infierno. Es preferible haber visitado otros lenguajes como el Visual Basic o el Delphi porque, de lo contrario, tendris toda la maravillosa complicacin de la programacin en Windows en vuestras manos. De todas formas, y despus de llevar un tiempo trabajando con las MFC, uno agradece todas las dificultades que te presenta. Aprendes a utilizar de verdad la orientacin a objetos ya que, obligatoriamente, has de utilizar cdigo que no es tuyo. Aprendes tambin unas normas de programacin mucho ms refinadas en cuanto a la declaracin de variables, funciones y dems y, cmo no, aprendes una cantidad ingente de ingls tcnico ;-D, pues la ayuda es algo que has de estar utilizando continuamente.

Cmo funciona un programa hecho en MFC?


Lo primero que tenemos que aceptar es que vamos a tener que utilizar un asistente para la creacin de cdigo. Dentro del excelente paquete de programacin que es Visual C++ (el compilador de Microsoft de C++ es el mejor que hay pese a quien pese), existen multitud de herramientas que nos ayudan a trabajar en la programacin de Windows. La ms valiosa de todas es, quizs, el AppWizard. El AppWizard, es un asistente que nos crea todos los archivos y cdigo necesario para comenzar a trabajar en una determinada aplicacin. Desde el AppWizard, podemos indicar si queremos hacer una aplicacin con soporte para ayuda, impresin, etc. Todo ello a travs de una serie de pasos que desembocarn en la creacin de todo el cdigo anteriormente descrito. Es ms, si una vez que hemos acabado con el AppWizard damos a "build" y ejecutamos, veremos que tenemos un programa ya hecho. De todas formas, a medida que uno va conociendo ms el "intrngulis" que se esconde en todo el cdigo que crea el AppWizard, podr ir eliminado los archivos que no necesite y adaptando el cdigo que se nos cree sin mayores complicaciones. Todo el cdigo que nos genera el AppWizard es, por as decirlo, perfecto. Todas las clases estn bien definidas y preparadas para ser utilizadas, modificadas o aumentadas. Como ya se coment ms arriba, el principal problema que se encuentra un programador tradicional de Windows es el de la "dureza" que supone enfrentarse a todo esa gran cantidad de cdigo que tiene delante de s. No hay por ningn lado una funcin WinMain o WinProc sobre las que empezar a "entender" lo que estamos viendo. En definitiva, estamos totalmente perdidos. Lo que realmente pasa, es que tanto la funcin WinMain como la WinProc, se encuentran en las bibliotecas de cdigo objeto que se enlazan cuando echamos a andar la compilacin de la aplicacin. En otras palabras, pese a que nunca veamos una funcin WinMain o WinProc en nuestro cdigo generado por el AppWizard, siempre existirn y se enlazarn. Como veis, si ya para programar en Windows con el API hay que cambiar totalmente la mentalidad, para programar en MFC y Windows, hay que hacer un coste adicional. Vuelvo a repetir, que la programacin en MFC bajo Windows no es fcil. Es mucho ms sencillo (como siempre, todo lo sencillo que t quieras) utilizar un paquete como Delphi y disfrutar antes de la programacin en Windows. Siendoos sinceros, a no ser que tengis un buen motivo para programar en MFC (utilizar toda la potencia de Windows y, claro est, saber utilizarla) y estis curtidos en la programacin del API bajo C o en el C++, pensarlo dos veces o bien... nunca os desanimis pese a los primeros y numerosos "palos". El mejor consejo que se puede dar es como el que se da cuando uno comienza a aprender el API bajo Windows;" no tengis un afn de conocimiento total". Aprender lo bsico y luego, ir haciendo pequeos programas que os obliguen a consultar temas de forma puntual. Slo de esta forma lograris avanzar. Y ya sabis, "a programar se aprende programando" y en Windows es IMPOSIBLE aprenderlo todo. Siempre vas a necesitar ayuda.

2 de 4

30/01/2012 11:08 a.m.

http://macedoniamagazine.frodrig.com/poo10.htm

Entonces, MFC API?.


Desde luego, si en el API lo nico que hacas eran aplicaciones, has de pasar YA a la programacin en MFC. De hecho, no creo que queden excesivos programadores de aplicaciones trabajando con el API directamente ya que es exageradamente tedioso. Si por el contrario, utilizas el API para crear juegos puedes seguir utilizndola perfectamente. Es ms!, las DirectX estn construidas en C por lo que su uso es mucho ms directo en la programacin tradicional bajo Windows. Sin embargo, y tal como me coment una vez Gonzalo Surez (Pyro Studios), una cosa es C++ y otra las MFC. Puedes seguir utilizando el C++ y crearte tus propias clases que encapsulen al API y las funciones de DirectX sin necesidad de acudir a las MFC. En la actualidad para el desarrollo de juegos, eso es lo que se hace pero, as mismo os digo, que para la creacin de tools o herramientas, se hace necesario utilizar herramientas ms visuales. Ah entraran las MFC, el Delphi, el Visual Basic, etc.

Visual C++; una herramienta excelente


Si para la generacin de cdigo, el Visual C++ nos aporta una excelente herramienta que nos evita el tener que crear cdigo global para todas las aplicaciones, (haciendo que entremos de lleno a trabajar en lo que a nosotros nos interesa) lo que es en s el paquete de desarrollo, slo se puede catalogar de estupendo. S, y pese a no querer hacer (Dios me libre) ningn tipo de publicidad a la casa del seor Gates, hay que decir que es una gozada trabajar con todas la potencia que te ofrece el Visual C++. Desde un potente gestor de clases como es el ClassWizard, a un Debugger impecable. Pasando, cmo no, por todas y cada una de las posibles opciones extra que nos brinda el entorno. Como os imaginaris, el ver por primera vez todo lo que nos ofrece este sistema de desarrollo asusta bastante pero, una vez ms, a base de la prctica y la dedicacin, os moveris "casi" como pez en el agua (siempre hay algo que se deja sin investigar los suficiente ;-). Uno de los principales problemas de todo lo que entraa la programacin bajo Windows utilizando el Visual C++ es, sin duda, su elevado coste para programadores "de a pie", que lo nico que buscan es una forma de ir adquiriendo experiencia de cara al futuro. Adquirir un paquete de Visual C++ supone un gran desembolso de dinero. Sin embargo, t no sers un pirata, no? . Lo que voy a hacer, es recomendaros, si sois estudiantes, que os hagis con una licencia de Microsoft para estudiantes. Es una buena forma de trabajar teniendo todo en orden sin que haga falta ser millonario. Como lo que no quiero es hacer publicidad de ninguna casa, simplemente os voy a comentar que os informis en el telfono de atencin al cliente de Microsoft sobre el tema. O en cualquier tienda especializada que seguro, os vendern una licencia por no ms de 15.000 pesetas. Algo, realmente interesante. Al menos, para personas que, como un servidor, no puede gastarse las cifras oficiales del producto ni en sueos pero que aborrece la piratera.

En definitiva
Como podis observar, este artculo no aporta ningn tipo de conocimiento tcnico. Est claramente orientado a la gente que ya trabaja en la programacin en Windows (principalmente con el API) o que estn preparando el salto a este sistema y no saben qu lenguaje escoger, para que se hagan una leve idea de cmo es el mundo "MFC". La programacin bajo Windows, al menos en C y C++, no es fcil si nunca se ha trabajado en un sistema de desarrollo en dicho Sistema Operativo. Si quieres comenzar a ver avances reales en t aprendizaje bajo Windows, puedes utilizar herramientas como el Delphi o el Visual Basic. De la primera decir que es excelente y que para muchas tareas resulta infinitamente ms cmoda que el Visual C++. De la segunda no puedo decir nada porque nunca la he utilizado. Por otro lado, si ests dispuesto a pasarte de seis meses a un ao pringando manuales y literatura de Visual C++, pues adelante. Es duro al comienzo pero merece la pena porque luego tienes ante ti un mundo de potencia infinita. Y bueno, esto ya se acaba. Quizs mi compaero David Isla "Cid", se anime y se ponga manos a la obra con un curso de Visual C++ con MFC. A qu esperas David? ;).

LTIMA REVISIN EN FEBRERO DE 1999

3 de 4

30/01/2012 11:08 a.m.

http://macedoniamagazine.frodrig.com/poo10.htm

[Aula Macedonia] [Curso de POO en C++]

AULA MACEDONIA a MACEDONIA Magazine

4 de 4

30/01/2012 11:08 a.m.

Das könnte Ihnen auch gefallen