heh!3:(3x002.heh):17/05/2000 << Back To heh!3


---------------------------------------------------- - Introduccion a la Programacion Orientada a Objetos - ---------------------------------------------------- por Joe El mundo de la programacion es muy amplio , hay muchos paradigmas y muchas tecnicas. No pretendo que esto sea un curso, si no una introduccion o simplemente un despertar para muchos de lo que es la programacion , y en este caso , la programacion orientada a objetos. Espero que lo disfruten leyendo tanto como yo lo disfrute haciendolo. (1) Introduccion ----------------- Conceptos basicos de Programacion Orientada a Objetos Que es orientacion a objetos? Es una forma de pensar basada en abstraccions e objetos o conceptos del mundo real. Una forma de organizar el software como una coleccion de objetos que interactuan entre si. Un objeto es una unidad que incorpora tanto datos como comportamientos Caracteristicas de POO -Identidad -Clasificacion -Herencia -Polimorfismo 1- Identidad - Interesa poder distinguir entre si dos objetos separados aun si aparecen como iguales entre si. Todo objeto respeta la identidad. Los objetos que no respetan la identidad son data values. Los atributos de un objeto son (en gral.) data values. 2- Clasificacion - Todos los objetos con caracteristicas comunes (atributos y operaciones) son descritos estructuralmente por una clase. 3- Herencia - Organizacion taxonomica entre clases que determina una relacion jerarquica entre ellas -------- Humano -------- ^ ------------------------- Hombre Mujer -------- --------- Las propiedades que tiene el objeto "Hombre" y "Mujeres" son caracteristicas propias mas las caracteristicas del objeto "Humano" 4- Polimorfismo - Una operacion puede estar asociada a transformaciones diferentes en diferentes clases ------ O1 ------ op1 ------ ^ | ------ O2 ------ op1 op2 ------ El objeto "O2" hereda las caracteristicas de "O1", con lo que hereda la operacion "op1" esta esta redefinida con una posible implementacion diferente para el objeto. A la implementacion que una clase le de a una operacion se lo llama metodo. Una operacion puede tener mas de un metodo en una misma jerarquia. (2) Practico ------------ Ahora vamos a implementar una clase "String" codificada en lenguaje C++, para introducir conceptos importantes, como homonimia de funciones, sobrecarga de operadores, y algo de memoria dinamica. 1. Definicion de la Clase class String { public : String( char * = "" ); // Constructor de conversion String( String & ); // Constructor de copia /* Los constructores son funciones con el mismo nombre de la clase que son llamados cuando son creados los objetos de dicha clase El constructor de conversion toma un "char *" vacio por defecto y lo convierte en un Objeto de la clase String con la misma cadena que el char * El constructor de copia, crea un objeto String copiandolo de un objeto ya existente. Hay 2 constructores, ha esto se le llama homonia de funciones, y en este caso en particular se le llama homonimia de constructores. El compilador elije la funcion adecuada de acuerdo a los parametros pasados. */ ~String(); // Destructor /* El destructor es una funci≤n con el mismo nombre que la clase pero con un ~ adelante Los destructores son llamados automaticamente cuando un objeto se sale de alcance, por ejemplo para liberar memoria. Solo puede haber un solo destructor. */ String &operator= ( String &); String &operator+=( String &); int operator!(); int operator==( String & ); int operator!=( String & ); int operator< ( String & ); int operator> ( String & ); int operator>=( String & ); int operator<=( String & ); String &operator()(int, int); /* Estas funciones sobrecargan distintos operadores para implementar funciones tales como comparaciones entre String, ver si un String es vacio, concatenar Strings, asignar valores y obtener un SubString a partir de un String */ int PerteneceStr( String & ); int StringLargo(); /* Dos funciones mas , para ver si un string es substring de otro, y para saber el largo de un objeto de la clase. */ private : char *caracter; int largo; /* Estos son los miembro privados de la clase. Cuando es usada la clase no es posible acceder a ellos. Estas dos lineas definen la representacion interna de un String. Un String tiene un puntero a un char, representando la cadena de caracteres ( Un array definido dinamicamente de chars ) Tambien tiene un campo "largo" que representa el largo de la cadena, si incluir el clasico "\0" en c, que es el final de la cadena */ }; 2. Implementacion de la Clase #include <string.h> #include "string2.h" //------------------------------------------------------------------------------ /* Constructor de conversion Asigno los campos del objeto implicito, con el largo del "char * c " usando la funcion strlen() de la biblioteca string para el manejo de "char *" Creo dinamicamente el array de chars de largo = "largo + 1" por el largo de la cadena mas el caracter final. Luego copio el valor del parametro c, al campo caracter del objeto implicito. */ String::String( char *c ) { largo = strlen( c ); caracter = new char[largo + 1]; strcpy( caracter, c ); } //------------------------------------------------------------------------------ /* Constructor de copia Se hace lo mismo que en la anterior , con la diferencia que el parametro ya es un objeto de la clase, asi que simplemente accedo a la estructura para obtener el largo y la cadena de caracteres */ String::String( String &c ) { largo = c.largo; caracter = new char[largo + 1]; strcpy( caracter, c.caracter ); } //------------------------------------------------------------------------------ /* Destructor Libero la memoria asignada para el campo caracter */ String::~String() { delete [] caracter; } //------------------------------------------------------------------------------ /* Operador = La operacion de asignacion se realiza igual que el constructor de copia Las diferencias son : 1║ se compara con el objeto implicito , si no es el mismo se asigna El objeto implicito se representa con "this", por ejemplo en la linea de codigo usando la clase: s1 = s2, el objeto implicito es s1. 2║ hay que borrar la cadena de caracteres para eso se usa el delete. Como la funcion debe retornar un String, se usa el return *this. */ String &String::operator= ( String &c ) { if (&c != this) { delete [] caracter; largo = c.largo; caracter = new char [largo + 1]; strcpy( caracter, c.caracter ); } return *this; } //------------------------------------------------------------------------------ /* Operador de Concatenación Para esta operacion uso una variable auxiliar y le asigno el valor del campo caracter Luego creo el nuevo espacio para la cadena, a partir del nuevo largo "largo += c.largo" Luego copio la cadena anterior, y le concateno la nueva. Por ultimo libero la memoria usada por la variable auxiliar */ String &String::operator+=( String &c ) { char *aux = caracter; largo += c.largo; caracter = new char[largo + 1]; strcpy ( caracter, aux ); strcat ( caracter, c.caracter ); delete [] aux; return *this; } //------------------------------------------------------------------------------ /* String Vacφo? Determina si el String esta vacio solo mirando el valor del largo del String */ int String::operator!() { return largo == 0; } //------------------------------------------------------------------------------ /* Operadores ==, !=, <, >, <=, >= Estas operaciones se implementan recurriendo a la funcion strcmp, y quedan realmente muy faciles de hacer */ int String::operator==( String &c ) { return strcmp( caracter, c.caracter ) == 0; } int String::operator!=( String &c ) { return strcmp( caracter, c.caracter ) != 0; } int String::operator<( String &c) { return strcmp( caracter, c.caracter ) < 0; } int String::operator>( String &c ) { return strcmp( caracter, c.caracter ) > 0; } int String::operator>=( String &c ) { return strcmp( caracter, c.caracter ) >= 0; } int String::operator<=( String &c ) { return strcmp( caracter, c.caracter ) <= 0; } //------------------------------------------------------------------------------ /* SubString Sin duda esta es la funcion mas dificil de implentar, lo hacemos sobrecargando los () para poder hacer algo asi: s1 = s2( 3 , 5). Esto indica que asigne a s1 el substring de s2 que empieza en el caracter 3 , y le copie los 5 siguientes caracteres partiendo desde ahi. Necesito una variable que es un puntero a un String y otra para saber el taman(i)o del nuevo String. El primer paso es calcular el largo del substring mirando que los parametros primero y cuantos no se salgan de rango, o sea que el valor inicial para obtener el substring no sea mayor que el largo de String. Si la variable no esta en rango , retorno un String vacio. Luego asigno los tama±os al nuevo String. Mediante un loop for , realizo la asignacion caracter a caracter, vigilando que sean los pedidos para eso , utilizamos la variables i, j. Lo unico que falta es colocarle al nuevo String el caracter "\0" para el fin de la cadena. Se lo asigno sacandolo del ultimo lugar del String implicito, aunque podria hacerlo directamente. */ String &String::operator()(int primero, int cuantos ) { String *pedazo; int grande; pedazo = new String; if ((primero >= 0) && (primero <= largo)) { if (( cuantos == 0) || (primero + cuantos > largo)) grande = largo - primero + 1; else grande = cuantos + 1; delete pedazo->caracter; pedazo->largo = grande; pedazo->caracter = new char[grande]; int j = 0; for ( int i = primero; i < primero + grande - 1; i ++ ) { pedazo->caracter[j] = caracter[i]; j++; } pedazo->caracter[j] = caracter[largo]; } return *pedazo; } //------------------------------------------------------------------------------ /* Determina si una String es SubString de otro Esta funcion la implementamos mediante un truquito gracias a la funcion strstr() La mencionada funcion lo que hace es buscar una ocurrencia del string dado y retornar el substring a partir de esa ocurrencia. Si no encuentra nada retorna NULL. Aprovechando esto, hago una llamada a esta funcion, usando una variable auxiliar. Si esta variable auxiliar es NULL , el String no es SubString del segundo. */ int String::PerteneceStr( String &c ) { char * aux; aux = strstr( caracter, c.caracter ); if ( aux == NULL ) return 0; else return 1; } //------------------------------------------------------------------------------ /* Largo de un String Simplemente retorno el campo largo */ int String::StringLargo() { return largo; } //------------------------------------------------------------------------------ Con esta Clase String se podran hacer cosas como esta: String s1, s2, s3; int l; s1 = "Hola"; s2 = " , como te va? "; if ( s1 < s2 ) .... if ( s1 == "Hola" ) .... s1 += s2; s3 = s1( 2, 5 ); l = s3.StringLargo(); y asi usando todas las funciones definidas para la clase, con lo que el manejo de String se vuelve muy facil y no tan pobre como el uso de punteros a char. Espero no haber aburrido a nadie con esto, y que les resulte divertido, aunque sea didactico el articulo. Un especial saludo a mis amigos: T@uRuX, highLevel, cYbErX, CachoMan, Ensablador, Morty y a mis hermanos: La Secta Band. Joe joe_joe@i.com.uy