Notas POO 2008 PDF
Notas POO 2008 PDF
Notas POO 2008 PDF
A OBJETOS
CON C++, JAVA Y RUBY
Notas de clase
C++
Elaborado por:
Carlos Alberto Fernández y Fernández
Instituto de Electrónica y Computación
Universidad Tecnológica de la Mixteca
Primavera 2008
Programación Orientada a Objetos
con C++, Java y Ruby
Contenido
Eclipse ................................................................................................................ 12
Características de C++...................................................................................... 15
Comentarios en C++........................................................................................ 15
Flujo de entrada/salida..................................................................................... 15
Funciones en línea............................................................................................ 16
Declaraciones de variables............................................................................... 18
Operador de resolución de alcance .................................................................. 19
Valores por Default .......................................................................................... 21
Parámetros por referencia................................................................................ 23
Variables de referencia ................................................................................... 24
Asignación de memoria en C++....................................................................... 26
Plantillas .......................................................................................................... 30
Introducción a la programación orientada a objetos [2, 3] ............................ 34
Programación no estructurada ......................................................................... 34
Programación procedural ................................................................................ 34
Programación modular..................................................................................... 35
Datos y Operaciones separados ....................................................................... 36
Programación orientada a objetos ................................................................... 37
Tipos de Datos Abstractos ................................................................................ 38
Los Problemas................................................................................................ 38
Tipos de Datos Abstractos y Orientación a Objetos ....................................... 39
Conceptos de básicos de objetos....................................................................... 40
Lenguajes de programación orientada a objetos .............................................. 43
C..................................................................................................................... 44
Introducción a Java........................................................................................... 46
Origen............................................................................................................... 46
Características de diseño.................................................................................. 47
Simple y familiar............................................................................................ 47
Orientado a Objetos........................................................................................ 48
Independiente de la plataforma....................................................................... 48
Portable .......................................................................................................... 49
Robusto .......................................................................................................... 49
Diferencias entre Java y C++ .......................................................................... 51
Archivos .java y .class ...................................................................................... 53
Programas generados con java ........................................................................ 53
El Java Developer’s Kit .................................................................................... 54
Compilación ................................................................................................... 54
“Hola Mundo” ................................................................................................. 56
Hola mundo básico en Java ............................................................................ 56
Hola mundo básico en C++ ............................................................................ 57
Hola mundo en un Java Applet....................................................................... 57
Archivo HTML .............................................................................................. 59
Ejecución........................................................................................................ 59
Hola mundo en Eclipse................................................................................... 60
Fundamentos del Lenguaje Java...................................................................... 61
Comentarios ..................................................................................................... 61
Tipos de datos................................................................................................... 62
Tipos de datos simples ................................................................................... 63
Referencias a objetos...................................................................................... 64
Identificadores .................................................................................................. 64
Variables .......................................................................................................... 65
Ámbito de una variable. ................................................................................. 66
Operadores ....................................................................................................... 69
Operadores aritméticos:.................................................................................. 69
Operadores relacionales: ................................................................................ 71
Operadores lógicos:........................................................................................ 72
Operadores de bits:......................................................................................... 73
Operadores de asignación:.............................................................................. 74
Precedencia de operadores en Java................................................................. 74
Valores literales................................................................................................ 75
Literales lógicos ............................................................................................. 75
Literales de tipo entero ................................................................................... 76
Literales de tipo real ....................................................................................... 76
Literales de tipo carácter ................................................................................ 77
Literales de tipo String ................................................................................... 78
Estructuras de control ...................................................................................... 79
Estructuras condicionales ............................................................................... 79
Ciclos. ............................................................................................................ 83
Saltos.............................................................................................................. 87
Arreglos ............................................................................................................ 88
Enumeraciones ................................................................................................. 92
Introducción a Ruby ......................................................................................... 94
Características ................................................................................................. 94
Comparado con C........................................................................................... 95
Comparado con C++ ...................................................................................... 96
Comparado con Java ...................................................................................... 97
Herramientas .................................................................................................... 98
Ruby: Fundamentos del lenguaje..................................................................... 99
Convenciones léxicas........................................................................................ 99
Literales.......................................................................................................... 100
Variables ........................................................................................................ 101
Operadores ..................................................................................................... 103
Carlos Alberto Fernández y Fernández
-4-
Programación Orientada a Objetos
con C++, Java y Ruby
Mixins............................................................................................................... 255
Referencias....................................................................................................... 413
Eclipse
5. Plug in para Ruby (RDT – Rubt Development Tools) si se quiere usar Ruby
con Eclipse
Si el CDT esta bien instalado debe ser posible crear proyectos de C/C++,
compilarlos, ejecutarlos y depurarlos dentro del ambiente de Eclipse.
Características de C++
Comentarios en C++
/* comentario en C */
Flujo de entrada/salida
printf("Número: ");
scanf("%d", &num);
printf("El valor leído es: " %d\n", num);
Funciones en línea
Declaración:
inline <declaración de la función>
Ejemplo:
Nota: Las funciones inline tienen conflictos con los prototipos, así que
deben declararse completas sin prototipo en el archivo .h. Además, si la función
hace uso de otra función en donde se expanda la función debe tener los include
correspondientes a esas funciones utilizadas.
Declaraciones de variables
Ejemplo:
#include <iostream>
int main() {
int i=0;
return 0;
}
#include <iostream>
int main() {
int i=0;
return 0;
}
Ejemplo:
float h;
Carlos Alberto Fernández y Fernández
- 19 -
Programación Orientada a Objetos
con C++, Java y Ruby
void g(int h) {
float a;
int b;
Las funciones en C++ pueden tener valores por default. Estos valores son
los que toman los parámetros en caso de que en una llamada a la función no se
encuentren especificados.
Los valores por omisión deben encontrarse en los parámetros que estén más
a la derecha. Del mismo modo, en la llamada se deben empezar a omitir los
valores de la extrema derecha.
Ejemplo:
#include <iostream>
int main () {
cout<<"valor 1: "<<punto()<<'\n';
cout<<"valor 2: "<<punto(1)<<'\n';
cout<<"valor 3: "<<punto(1,3)<<'\n';
getchar();
return 0;
}
if(y!=4)
return y;
if(x!=5)
return x;
return x+y;
}
punto( , 8);
int b=1;
int f(int);
int h(int x=f(b)); // argumento default f(::b)
int main () {
b=5;
cout<<b<<endl;
{
int b=3;
cout<<b<<endl;
cout<<h(); //h(f(::b))
}
return 0;
}
En C todos los pasos de parámetros son por valor, aunque se pueden enviar
parámetros "por referencia" al enviar por valor la dirección de un dato (variable,
estructura, objeto), de manera que se pueda accesar directamente el área de
memoria del dato del que se recibió su dirección.
C++ introduce parámetros por referencia reales. La manera en que se
definen es agregando el símbolo & de la misma manera que se coloca el *:
después del tipo de dato en el prototipo y en la declaración de la función.
Ejemplo:
#include <iostream>
int porValor(int);
void porApuntador(int *);
void porReferencia( int &);
int main() {
int x=2;
cout << "x= " << x << " antes de llamada a porValor \n"
<< "Regresado por la función: "<< porValor(x)<<endl
<< "x= " << x << " despues de la llamada a
porValor\n\n";
int y=3;
cout << "y= " << y << " antes de llamada a
porApuntador\n";
porApuntador(&y);
cout << "y= " << y << " despues de la llamada a
porApuntador\n\n";
int z=4;
cout << "z= " << z << " antes de llamada a porReferencia
\n";
porReferencia(z);
cout<< "z= " << z << " despues de la llamada a
porReferencia\n\n";
return 0;
}
Variables de referencia
También puede declararse una variable por referencia que puede ser
utilizada como un seudónimo o alias. Ejemplo:
Ejemplo:
// variable por referencia
#include <iostream>
int main() {
int x=2, &y=x, z=8;
y=10;
cout << "x= "<<x <<endl
<<"y= "<<y<<endl;
// Reasignar no esta permitido
/* &y=&z;
cout << "z= "<<z <<endl
<<"y= "<<y<<endl;
*/
y++;
cout << "z= "<<z <<endl
<<"y= "<<y<<endl;
return 0;
}
float *f;
f = (float *) malloc(sizeof(float));
. . .
free(f);
float *f;
f= new float;
. . .
delete f;
char *cad;
Carlos Alberto Fernández y Fernández
- 26 -
Programación Orientada a Objetos
con C++, Java y Ruby
Usar delete sin los corchetes para arreglos dinamicos puede no liberar
adecuadamente la memoria, sobre todo si son elementos de un tipo definido por el
usuario.
Ejemplo 1:
#include <iostream>
int main() {
int *p,*q;
if(!p) {
cout<<"No se pudo asignar memoria\n";
return 0;
}
*p=100;
cout<<endl<< *p<<endl;
Ejemplo 2:
#include <iostream>
int main() {
float *ap, *p=new float (3) ;
const int MAX=5;
ap= new float [MAX]; //asigna memoria
int i;
for(i=0; i<MAX; i++)
ap[i]=i * *p;
for(i=0; i<MAX; i++)
cout<<ap[i]<<endl;
delete p;
delete [] ap;
return 0;
}
Ejemplo 3:
#include <iostream>
typedef struct {
int n1,
n2,
n3;
}cPrueba;
int main() {
cPrueba *pr1, *pr2;
delete pr1;
delete pr2;
return 0;
}
Plantillas
Cada parámetro formal puede ser usado para sustituir a: tipos de datos básicos,
estructurados o definidos por el usuario, tipos de los argumentos, tipo de regreso
de la función y para variables dentro de la función.
Ejemplo 1:
#include <iostream>
int main(){
int a=10, b=20, c=0;
float x=44.1, y=22.3, z=0 ;
c=mayor(a, b);
z=mayor(x, y);
cout<<c<<" "<<z<<endl;
return 0;
}
Consideraciones:
• Cada parámetro formal debe aparecer en la lista de parámetros de la función al
menos una vez.
• No puede repetirse en la definición de la plantilla el nombre de un parámetro
formal.
• Tener cuidado al manejar mas de un parámetro en los templates.
Ejemplo 2:
#include <iostream>
int main() {
const int contEnt=4, contFlot=5, contCar=10;
int ent[]={1,2,3,4};
float flot[]={1.1, 2.2, 3.3, 4.4, 5.5};
char car[]={"Plantilla"};
return 0;
}
Ejemplo 3:
#include <iostream>
int main(){
c=mayor(a, b);
z=mayor(x, y);
cout<<c<<" "<<z<<endl;
//sin error al aumentar un parámetro formal.
z=mayor(x,b);
cout<<z<<endl;
z=mayor(a,y); //regresa entero pues a es entero (tipo T es
entero para
cout<<z<<endl; // este llamado.
z=mayor(y, a);
cout<<z<<endl;
return 0;
}
Programación no estructurada
Programación procedural
De este modo, un programa puede ser visto como una secuencia de llamadas
a procedimientos. El programa principal es responsable de pasar los datos a las
llamadas individuales, los datos son procesados por los procedimientos y, una vez
que el programa ha terminado, los datos resultantes son presentados.
Así, el flujo de datos puede ser ilustrado como una gráfica jerárquica, un
árbol, como se muestra en la figura para un programa sin subprocedimientos.
Programación modular
Cada módulo puede contener sus propios datos. Esto permite que cada módulo
maneje un estado interno que es modificado por las llamadas a procedimientos de
ese módulo.
Sin embargo, solamente hay un estado por módulo y cada módulo existe
cuando más una vez en todo el programa.
requerimientos. Por consecuencia, los programas se estructuran por los datos más
que por las operaciones.
Los datos especifican las operaciones válidas. Ahora, los módulos agrupan
representaciones de datos en forma conjunta.
En contraste con las otras técnicas, ahora tenemos una telaraña de objetos
interactuantes, cada uno de los cuáles manteniendo su propio estado.
Los Problemas
La primera cosa con la que uno se enfrenta cuando se escriben programas es
el problema.
Sin embargo, los problemas de la vida real son nebulosos y la primera cosa
que se tiene que hacer es tratar de entender el problema para separar los detalles
esenciales de los no esenciales: tratando de obtener tu propia perspectiva
abstracta, o modelo, del problema. Este proceso de modelado se llama abstracción
y se ilustra en la Figura:
El modelo define una perspectiva abstracta del problema. Esto implica que
el modelo se enfoca solamente en aspectos relacionados con el problema y que
uno trata de definir propiedades del problema. Estas propiedades incluyen
por el problema.
Aspectos principales:
1) Objetos.
• El objeto es la entidad básica del modelo orientado a objetos.
• El objeto integra una estructura de datos (atributos) y un comportamiento
(operaciones).
• Se distinguen entre sí por medio de su propia identidad, aunque internamente
los valores de sus atributos sean iguales.
2) Clasificación.
• Las clases describen posibles objetos, con una estructura y comportamiento
común.
• Los objetos que contienen los mismos atributos y operaciones pertenecen a la
misma clase.
• La estructura de clases integra las operaciones con los atributos a los cuales se
aplican.
3) Instanciación.
• El proceso de crear objetos que pertenecen a una clase se denomina
instanciación.
• Pueden ser instanciados un número indefinido de objetos de cierta clase.
4) Generalización.
• En una jerarquía de clases, se comparten atributos y operaciones entre clases
basados en la generalización de clases.
• La jerarquía de generalización se construye mediante la herencia.
• Las clases más generales se conocen como superclases.
• Las clases más especializadas se conocen como subclases. La herencia puede
ser simple o múltiple.
5) Abstracción.
• La abstracción se concentra en lo primordial de una entidad y no en sus
propiedades secundarias.
• Además en lo que el objeto hace y no en cómo lo hace.
• Se da énfasis a cuales son los objetos y no cómo son usados.
6) Encapsulación.
• Encapsulación o encapsulamiento es la separación de las propiedades externas
de un objeto de los detalles de implementación internos del objeto.
• Al separar la interfaz del objeto de su implementación, se limita la complejidad
al mostrarse sólo la información relevante.
• Disminuye el impacto a cambios en la implementación, ya que los cambios a
las propiedades internas del objeto no afectan su interacción externa.
7) Modularidad.
• El encapsulamiento de los objetos trae como consecuencia una gran
modularidad.
• Cada módulo se concentra en una sola clase de objetos.
• Los módulos tienden a ser pequeños y concisos.
• La modularidad facilita encontrar y corregir problemas.
• La complejidad del sistema se reduce facilitando su mantenimiento.
8) Extensibilidad.
• La extensibilidad permite hacer cambios en el sistema sin afectar lo que ya
existe.
• Nuevas clases pueden ser definidas sin tener que cambiar la interfaz del resto
del sistema.
9) Polimorfismo.
• El polimorfismo es la característica de definir las mismas operaciones con
diferente comportamiento en diferentes clases.
• Se permite llamar una operación sin preocuparse de cuál implementación es
requerida en que clase, siendo responsabilidad de la jerarquía de clases y no
del programador.
General
Typing
Language model of Influences Paradigm(s) Introduced
discipline
execution
concurrent,
Algol, Pascal, distributed, static,
C++ (Ada 95), generic, strong,
Ada Compilation 1983
Smalltalk (Ada 95), imperative, safe,
Java (Ada 2005) object- nominative
oriented
imperative, static,
C, Simula, Algol
C++ Compilation object- strong, 1985
68
oriented, unsafe,
1
Lenguajes de Programación Orientada a Objetos
2
A partir de la version 5 (1.5) de Java
3
Idem
4
La tabla completa puede ser vista en:
http://en.wikipedia.org/wiki/Comparison_of_programming_languages
Carlos Alberto Fernández y Fernández
- 44 -
Programación Orientada a Objetos
con C++, Java y Ruby
generic nominative
imperative,
object- static,
JIT Delphi, Java, C++, oriented, strong,
C# 2000
compilation Ruby generic, both safe
multi- and unsafe
platform
static,
imperative,
strong,
object-
Eiffel Compilation Ada, Simula safe, 1985
oriented,
nominative,
generic
contracts
imperative,
object-
Interpretation
C++, Objective-C, oriented, static,
Java / JIT 1994
C#[2] multi- strong
compilation
platform,
generic
static,
imperative, strong, safe
Object
Compilation Pascal object- (but unsafe 1985
Pascal
oriented allowed),
nominative
imperative,
object-
dynamic
oriented,
Ruby Interpretation Smalltalk,Perl,Lisp (duck), 1995
functional,
strong
aspect-
oriented
object-
oriented,
functional, dynamic,
JIT
Smalltalk Sketchpad, Simula concurrent, strong, 1971
compilation
event-driven, safe, duck
imperative,
declarative
Introducción a Java
Origen
El interés que generó Java en la industria fue mucho, tal que nunca un
lenguaje de programación había sido adoptado tan rápido por la comunidad de
desarrolladores. Las principales razones por las que Java es aceptado tan rápido:
Características de diseño
• Simple y familiar.
• Orientado a objetos.
• Independiente de la plataforma
• Portable
• Robusto.
• Seguro.
• Multihilos.
Simple y familiar
Orientado a Objetos
Hardware
5
Los puristas objetarían que no es totalmente orientado a objetos. En un sentido estricto Smalltalk es un
lenguaje “más” puro, ya que ahí hasta los tipos de datos básicos son considerados objetos.
Carlos Alberto Fernández y Fernández
- 48 -
Programación Orientada a Objetos
con C++, Java y Ruby
Portable
Una razón por la que los programas en Java son portables es precisamente
que el lenguaje es independiente de la plataforma.
Robusto
6
Más adelante en el curso se ahondará en el tema.
Carlos Alberto Fernández y Fernández
- 49 -
Programación Orientada a Objetos
con C++, Java y Ruby
• Las cadenas no terminan con ‘\0’. Las cadenas en C y C++ terminan con
‘\0’ que corresponde al valor en ASCII 0, ya que en estos lenguajes no
existe la cadena como un tipo de dato estándar y se construye a partir de
arreglos de caracteres. En Java una cadena es un objeto de la clase String y
no necesita ese carácter para indicar su finalización.
• No tiene herencia múltiple. Java solo cuenta con herencia simple, con lo
que pierde ciertas capacidades de generalización que son subsanadas a
través del uso de interfaces. El equipo de desarrollo de Java explica que esto
simplifica el lenguaje y evita la ambigüedad natural generada por la
herencia múltiple.
Además:
7
Garbage Collector.
Carlos Alberto Fernández y Fernández
- 52 -
Programación Orientada a Objetos
con C++, Java y Ruby
Un archivo de código fuente debe tener solo una clase principal, y esta debe
tener exactamente el mismo nombre que el del archivo .java. Por ejemplo, si
tengo una clase que se llama Alumno, el archivo de código fuente se llamará
Alumno.java. Al compilar, el archivo resultante será Alumno.class.
Por un lado están las aplicaciones, las cuales son programas standalone,
escritos en Java y ejecutados por un intérprete del código de bytes desde la línea
de comandos del sistema.
Por otra parte, los Applets, que son pequeñas aplicaciones escritas en Java,
las cuales siguen un conjunto de convenciones que les permiten ejecutarse dentro
de un navegador. Estos applets siempre están incrustados en una página html.
• Una aplicación debe definir una clase que contenga el método main(),
que controla su ejecución. Un applet no usa el método main(); su
8
Se presenta la división clásica de los programas de Java, aunque existen algunas otras opciones no son
relevantes en este curso.
Carlos Alberto Fernández y Fernández
- 53 -
Programación Orientada a Objetos
con C++, Java y Ruby
Compilación
Ejemplo:
9
Java Virtual Machine
10
Este kit de desarrollo es gratuito y puede obtenerse de la dirección proporcionada al final de este
documento. Aunque en este curso se usara Eclipse, el jdk debe estar instalado para poder usar Java en
Eclipse.
Carlos Alberto Fernández y Fernández
- 54 -
Programación Orientada a Objetos
con C++, Java y Ruby
Sintaxis:
javac [opciones] <archivo1.java>
“Hola Mundo”
%javac HolaMundo.java
11
Se asume que el jdk se encuentra instalado y que el PATH tiene indicado el directorio bin del jdk para que
encuentre el programa javac. También es recomendable añadir nuestro directorio de programas de java a una
variable de ambiente llamada CLASSPATH.
Carlos Alberto Fernández y Fernández
- 56 -
Programación Orientada a Objetos
con C++, Java y Ruby
int main(){
cout << "Hola Mundo!" << endl;
return 0;
}
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Color;
es equivalente a:
import java.util.Hashtable; //importar esta clase
...
Hashtable miTable = new Hashtable();
import java.awt.*;
Archivo HTML
Ejecución
% java HolaMundo
% appletviewer hola.html
Probar estos ejemplos en Eclipse debe crearse un proyecto en Java. Como en Java
no hay funciones independientes, los archivos que se añaden al proyecto son
archivos de clases. Al añadir una clase al proyecto aparece la siguiente ventana:
Comentarios
• Si el comentario que se desea escribir es de una sola línea, basta con poner
dos barras inclinadas //. Por ejemplo:
for (i=0; i<20;i++) // comentario de ciclo
{
System.out.println(“Adiós”);
}
Tipos de datos
Los tipos de datos simples son aquellos que pueden utilizarse directamente
en un programa, sin necesidad del uso de clases. Estos tipos son:
• byte
• short
• int
• long
• float
• double
• char
• boolean
El segundo tipo está formado por todos los demás. Se les llama referencias
porque en realidad lo que se almacena en los mismos son punteros a áreas de
memoria donde se encuentran almacenadas las estructuras de datos que los
soportan. Dentro de este grupo se encuentran las clases (objetos) y también se
incluyen las interfaces, los vectores y las cadenas o Strings.
12
C-2 = Complemento a dos.
Carlos Alberto Fernández y Fernández
- 63 -
Programación Orientada a Objetos
con C++, Java y Ruby
entero de tipo int siempre tendrá 4 bytes, por lo que no tendremos resultados
inesperados al migrar un programa de un sistema operativo a otro.
Eso sí, Java no realiza una comprobación de los rangos. Por ejemplo: si a
una variable de tipo short con el valor 32.767 se le suma 1, el resultado será -
32.768 y no se producirá ningún error de ejecución.
Los valores que pueden asignarse a variables y que pueden ser utilizados en
expresiones directamente reciben el nombre de literales.
Referencias a objetos
Identificadores
Los identificadores son los nombres que se les da a las variables, clases,
interfaces, atributos y métodos de un programa.
Variables
Ejemplo:
int x;
int x = 0;
• Variable local.
• Atributo.
• Parámetro de un método.
• Parámetro de un manejador de excepciones13.
Variables locales. Una variable local se declara dentro del cuerpo de un método
de una clase y es visible únicamente dentro de dicho método. Se puede declarar
en cualquier lugar del cuerpo, incluso después de instrucciones ejecutables,
aunque es una buena costumbre declararlas justo al principio.
Ejemplo:
class Caracter {
char ch;
public Caracter(char c) {
ch=c;
}
como único parámetro el nombre del constructor, que será el procedimiento que
asigna valor a ese objeto recién instanciado.
Ejemplo:
int x,y,z; //Declara tres variables x, y, z de tipo entero.
int x=0,y=0,z=3;
Las variables locales pueden ser antecedidas por la palabra reservada final.
En ese caso, sólo permiten que se les asigne un valor una única vez14.
Ejemplo:
14
final es utilizado para declarar algo similar a las constantes.
15
Esta posibilidad aparece por primera vez en la versión 1.1 del jdk.
Carlos Alberto Fernández y Fernández
- 68 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
final int x;
...
x=y+2;
Operadores
Operadores aritméticos:
Ejemplo:
a = 1; a = 1;
b = 2 + a++; b = 2 + ++a;
Operadores relacionales:
Ejemplo:
public class Relacional {
public static void main(String arg[]) {
double op1,op2;
op1=1.34;
op2=1.35;
System.out.println("op1="+op1+" op2="+op2);
System.out.println("op1>op2 = "+(op1>op2));
System.out.println("op1<op2 = "+(op1<op2));
System.out.println("op1==op2 = "+(op1==op2));
System.out.println("op1!=op2 = "+(op1!=op2));
char op3,op4;
op3='a'; op4='b';
System.out.println("'a'>'b' = "+(op3>op4));
}
}
Operadores lógicos:
Ejemplo:
public class Bool {
public static void main ( String argumentos[] ) {
boolean a=true;
boolean b=true;
boolean c=false;
boolean d=false;
System.out.println("true Y true = " + (a && b) );
System.out.println("true Y false = " + (a && c) );
System.out.println("false Y false = " + (c && d) );
System.out.println("true O true = " + (a || b) );
System.out.println("true O false = " + (a || c) );
System.out.println("false O false = " + (c || d) );
System.out.println("NO true = " + !a);
System.out.println("NO false = " + !c);
System.out.println("(3 > 4) Y true = " + ((3 >4) && a)
);
}
}
Operadores de bits:
Los operadores de bits actúan sobre valores enteros (byte, short, int y long)
o caracteres (char).
Ejemplo:
public class Bits {
public static void main ( String argumentos[] ) {
byte a=12;
byte b=-12;
byte c=6;
System.out.println("12 >> 2 = " + (a >> 2) );
System.out.println("-12 >> 2 = " + (b >> 2) );
System.out.println("-12 >>> 2 = " + (b >>> 2) );
System.out.println("12 << 2 = " + (a << 2) );
System.out.println("-12 << 2 = " + (b << 2) );
System.out.println("12 & 6 = " + (a & c) );
System.out.println("12 | 6 = " + (a | c) );
System.out.println("12 ^ 6 = " + (a ^ c) );
System.out.println("~12 = " + ~a);
}
}
Operadores de asignación:
op1 = Expresión;
Suma y resta + -
Desplazamiento de bits << >> >>>
Relacionales < > <= >=
Igualdad y desigualdad == !=
AND a nivel de bits &
XOR a nivel de bits ^
OR a nivel de bits |
AND lógico &&
OR lógico ||
Condicional terciaria ? :
Asignación = += -= *= /= %= ^= &= |= >>= <<=
>>>=
Valores literales
• Lógicos (boolean).
• Carácter (char).
• Enteros (byte, short, int y long).
• Reales (double y float).
• Cadenas de caracteres (String).
Literales lógicos
Ejemplo:
Son byte, short, int y long pueden expresarse en decimal (base 10), octal
(base 8) o hexadecimal (base 16). Además, puede añadirse al final del mismo la
letra L para indicar que el entero es considerado como long (64 bits).
Los literales de tipo real sirven para indicar valores float o double. A
diferencia de los literales de tipo entero, no pueden expresarse en octal o
hexadecimal.
Ejemplos equivalentes:
3.1415
0.31415e1
.31415e1
0.031415E+2
.031415e2
314.15e-2
31415E-4
Al igual que los literales que representan enteros, se puede poner una letra
como sufijo. Esta letra puede ser una F o una D (mayúscula o minúscula
indistintamente).
Ejemplo:
3.1415F
.031415d
Ejemplo:
System.out.println("Primera línea \n Segunda línea del
string\n");
System.out.println("Hol\u0061");
Primera línea
Segunda línea del string
Hola
Estructuras de control
Estructuras condicionales
• Estructura if-else.
• Estructura switch.
if-else
Forma simple:
if (<expresión>)
<Bloque instrucciones>
El bloque de instrucciones se ejecuta si, y sólo si, la expresión (que debe ser
lógica) se evalúa a verdadero, es decir, se cumple una determinada condición.
Carlos Alberto Fernández y Fernández
- 79 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
if (cont == 0)
System.out.println("he llegado a cero");
Forma bicondicional:
if (<expresión>)
<Bloque instrucciones 1>
else
<Bloque instrucciones 2>
Ejemplo:
if (cont == 0)
System.out.println("he llegado a cero");
else
System.out.println("no he llegado a cero");
switch
Sintaxis:
switch (<expresión>) {
case <valor1>: <instrucciones1>;
Carlos Alberto Fernández y Fernández
- 80 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
switch (<expresión>) {
Ejemplo:
default: instruccionesPorDefecto;
Ciclos.
• Ciclo for.
• Ciclo do-while.
• Ciclo while.
Como regla general puede decirse que se utilizará el ciclo for cuando se
conozca de antemano el número exacto de veces que ha de repetirse un
determinado bloque de instrucciones. Se utilizará el ciclo do-while cuando no se
conoce exactamente el número de veces que se ejecutará el ciclo pero se sabe que
por lo menos se ha de ejecutar una. Se utilizará el ciclo while cuando es posible
que no deba ejecutarse ninguna vez. Con mayor o menor esfuerzo, puede
utilizarse cualquiera de ellas indistintamente.
Ciclo for.
Sintaxis:
Cualquiera de estas tres cláusulas puede estar vacía, aunque siempre hay que
poner los puntos y coma ( ; ).
Ejemplo:
// siempre se mostrarán, por lo menos, los dos primeros
//términos
public class Fibonacci {
public static void main(String argumentos[]) {
int numTerm,v1=1,v2=1,aux,cont;
if (argumentos.length<1) {
System.out.println("Uso: Fibonacci num");
System.out.println("Donde num = nº de términos");
}
else {
numTerm=Integer.valueOf(argumentos[0]).intValue();
System.out.print("1,1");
for (cont=2;cont<numTerm;cont++) {
aux=v2;
v2+=v1;
v1=aux;
System.out.print(","+v2);
}
System.out.println();
}
}
}
Ciclo do-while.
Sintaxis:
do
<bloque instrucciones>
while (<Expresión>);
En este tipo de ciclo, el bloque instrucciones se ejecuta siempre una vez por
lo menos, y el bloque de instrucciones se ejecutará mientras <Expresión> se
evalúe como verdadero. Por lo tanto, entre las instrucciones que se repiten deberá
existir alguna que, en algún momento, haga que la expresión se evalúe como
falso, de lo contrario el ciclo sería infinito.
Ejemplo:
Ciclo while.
Sintaxis:
while (<Expresión>)
<bloque instrucciones>
Ejemplo:
//Fibonacci:
class Fibonacci3 {
public static void main(String argumentos[]) {
int numTerm,v1=1,v2=1,aux,cont=2;
if (argumentos.length<1) {
System.out.println("Uso: Fibonacci num");
System.out.println("Donde num = nº de términos");
}
else {
numTerm=Integer.valueOf(argumentos[0]).intValue();
System.out.print("1,1");
while (cont++<numTerm) {
aux=v2;
v2+=v1;
v1=aux;
System.out.print(","+v2);
}
System.out.println();
}
}
}
Saltos
break. La instrucción break sirve para abandonar una estructura de control, tanto
de las alternativas (if-else y switch) como de las repetitivas o ciclos (for, do-while
y while). En el momento que se ejecuta la instrucción break, el control del
programa sale de la estructura en la que se encuentra.
Ejemplo:
class Break {
public static void main(String argumentos[]) {
int i;
for (i=1; i<=4; i++) {
if (i==3)
break;
System.out.println("Iteracion: "+i);
}
}
}
Ejemplo:
Arreglos
En Java, los arreglos son en realidad objetos y por lo tanto se puede llamar a
sus métodos. Existen dos formas equivalentes de declarar arreglos en Java:
tipo nombreDelArreglo[ ];
ó
tipo[ ] nombreDelArreglo;
Ejemplo:
int arreglo1[], arreglo2[], entero; //entero no es un arreglo
int[] otroArreglo;
Ejemplo:
int matriz[][];
int [][] otraMatriz;
Los arreglos, al igual que las demás variables pueden ser inicializados en el
momento de su declaración. En este caso, no es necesario especificar el número
de elementos máximo reservado. Se reserva el espacio justo para almacenar los
elementos añadidos en la declaración.
Ejemplo:
String Días[]={"Lunes","Martes","Miércoles","Jueves",
"Viernes","Sábado","Domingo"};
Ejemplo:
int matriz[][];
matriz = new int[4][7];
Carlos Alberto Fernández y Fernández
- 89 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
int vector[] = new int[5];
Ejemplo:
Ejemplo:
class Array1 {
public static void main (String argumentos[]) {
String colores[] = {"Rojo","Verde","Azul",
"Amarillo","Negro"};
int i;
for (i=0;i<colores.length;i++)
System.out.println(colores[i]);
}
}
Usando Java 5.0 (jdk 1.5) podemos simplificar el recorrido del arreglo:
public class Meses {
Con Eclipse, aparte de contar al menos con el jdk 1.5, la opción de compilación
debe estar ajustada para que revise que el código sea compatible con esa versión:
Enumeraciones
Ejemplo:
System.out.println("\nListado de temporadas:");
for(Temporada t: Temporada.values())
System.out.println("Temporada: " + t);
}
}
Introducción a Ruby
Características
Comparado con C
Similitudes
• Puedes programar proceduralmente si lo deseas, pero aún sera orientado a
objetos internamente.
• La mayoría de los operadores son los mismos. Pero no cuenta con ++ o --.
• Se pueden tener constantes, aunque no hay una instrucción const.
• Las cadenas van entre comillas y son mutables.
• Se cuenta con un depurador en línea.
Diferencias
• Los objetos tienen un tipo fuerte y las variables no tienen tipo.
• No cuenta con macros o preprocesador.
• No tiene enmascaramiento.
• No tiene apuntadores, ni aritmética de apuntadores.
• No tiene tupedef, sizeof, ni enumeraciones.
• No archivos de encabezados.
• No maneja #define. Pero puedas usar constantes.
• Es interpretado en tiempo de ejecución, por lo que no hay código compilado
o byt-code de ningún tipo.
• Cuenta con recolector de basura.
• Los argumentos son pasados por referencia, no por valor.
• No usa ‘;’ obligatoriamente para finalizar instrucciones
Similitudes
• Public, protected y private realizan actividades similares.
• Puedes poner tu código en módulos, similar a espacios de nombre en C++.
• Excepciones trabajan de forma similar.
Diferencias
• No hay referencias explícitas. En Ruby cada variable es un nombre
automáticamente desreferenciado para un objeto.
• El constructor es llamado initialize en lugar de usar el nombre de la clase.
• Todos los métodos son siempre virtuales.
• Nombres de atributos de clase siempre empiezan con @@.
• No es possible acceder directamente variables miembros. Todos los
atributos deben ser accedidos a mediante métodos.
• Se usa self en lugar de this.
• Algunos métodos terminan con ‘?’ o ‘!’. Es parte del nombre del método.
• No hay herencia multiple.
• Existen algunas convenciones forzadas (e.g.; nombre de clases empiezan
con mayúscula, variables inician con minuscula.)
• Solo dos tipos de clases contenedoras: Array y Hash.
• No hay conversiones de tipos automáticas.
Similitudes
• La memoria es manejada automáticamente mediante un recolector de
basura.
• Los objetos son fuertemente tipados.
• Hay métodos públicos, privados y protegidos.
• Tiene herramientas de documentación embebidas (la de Ruby se llama
RDoc). La documentación generada por rdoc se ve muy similar a la
generada por javadoc.
Diferencias
• No necesitas compilar tu código fuente. Directamente lo ejecutas.
• Hay distintos conjuntos de herramientas para interfaz gráfica
• Se usa la palabra clave end después de definir clases, en vez de tener que
poner llaves encerrando el código.
• Tienes require en vez de import.
• Todas las variables de instancia son privadas. Desde afuera, todo se accede
usando métodos.
• Los paréntesis en las llamadas a los métodos usualmente son opcionales y a
menudo son omitidos.
• Todo es un objeto, incluyendo los números como 2 y 3,14159.
• No hay validación estática de tipos de datos.
• Los nombres de variables son sólo etiquetas. No tienen un tipo de dato
asociado.
• No hay declaración de tipo de datos. Simplemente se asigna a nuevos
nombres de variable a medida que se necesita (por ejemplo a = [1,2,3] en
vez de int[] a = {1,2,3};).
Espacios en blanco
a +b
es interpretada como:
a (+b)
Carlos Alberto Fernández y Fernández
- 99 -
Programación Orientada a Objetos
con C++, Java y Ruby
Final de instrucciones
Comentarios
# Este es un comentario
Comentarios de más de una línea usan =begin y =end, los cuales deben estar al
comienzo de una línea:
=begin
Este es un comentatio
=end
Identificadores
Literales
Enteros
123 # decimal
0377 # octal
0xff # hexadecimal
0b1011 # binary
?a # código para 'a'
12345678901234567890 # Bignum: entero de longitud
infinita
Flotantes
123.4
1.0e6 # notación científica
4e+20 # exponencial
Cadenas
Una cadena es un arreglo de bytes y una instancia de la clase String:
Concatenación.
Variables
• Variable global
Carlos Alberto Fernández y Fernández
- 101 -
Programación Orientada a Objetos
con C++, Java y Ruby
• Variable de instancia
• Variable de clase
• Variable local
• Constante
y además:
• Pseudo-variable
Variable global
$soyGlobal
Variable de instancia
@soyVariableDeInstancia
Al igual que las variables globales, estas tienen el valor de nil si no han sido
inicializadas.
Variable de clase
@@variableDeClase
Estas variables deben ser inicializadas antes de que puedan ser usadas en los
métodos. El uso de una variable de clase no inicializada produce un error.
Ademas, estas clases son compartidas por descendientes de las clases donde
fueron definidas.
Variable local
Son válidas dentro del ambito local definido y deben empezar con una
minúscula o con el símbolo _. El ámbito puede ser el que defina una clase,
módulo, definición, do –end.
Constante
Deben empezar con una letra mayúscula y pueden ser definidas dentro de
una clase o módulo y serán visibles dentro de ese ámbito. Una constante
definida fuera de un clase o módulo será vista globalmente. Es posible reasignar
un valor a una constante, pero esto producirá una advertencia (pero no un error).
Pseudo-variable
Operadores
Asignación
Asignación paralela
Operadores lógicos
Un aspecto interesante aquí es que los operadores and y or tienen una precedencia
muy baja, de hecho tienen la menor de las precedencias entre los operadores.
Operador ternario
a? b : c
Carlos Alberto Fernández y Fernández
- 104 -
Programación Orientada a Objetos
con C++, Java y Ruby
Operador defined?
defined? variable
Por ejemplo:
defined? a
defined? $_
Prioridad de operadores
::
[]
**
+(unario) -(unario)
*/%
+-
<< >>
&
|^
> >= < <=
<=> == !=
&&
||
Carlos Alberto Fernández y Fernández
- 105 -
Programación Orientada a Objetos
con C++, Java y Ruby
?:
= (y operadores abreviados como +=, -=, etc.)
not
and or
...
!
not
&&
and
||
or
::
=
+=, -=, (y el resto de las asignaciones abreviadas)
?:
Arreglos
[] Arreglo vacío
ar1= []
El método size puede ser utilizado para conocer el número de elementos del
arreglo:
a.size # => 4
a[3] # => [4, 5, 6]
a[3].size # => 3
a[3][0] # => 4
Probando Ruby
Estructuras de control
Sintaxis:
if condicional [then]
instrucciones
[elsif condicional [then]
instrucciones]...
[else
instrucciones]
end
Ejemplos:
if x < 5 then
declaracion1
end
if x < 5 then
declaracion1
else
declaracion2
end
declaracion1 if y == 3
Sintaxis:
Ejemplos:
declaracion1 unless y != 3
Sintaxis:
case expresión
[when expresión[, expresión...] [then]
instrucciones]...
[else
instrucciones]
end
Ejemplo:
Sintaxis:
ó:
begin
instrucciones
end while condicional
Sintaxis:
ó:
instrucciones until condicional
ó:
begin
instrucciones
end until condicional
Sintaxis:
break. Termina un ciclo while o until. También finaliza un método con un bloque
asociado si es usado dentro del bloque, con el método regresando el valor de nulo.
BEGIN {
instrucciones
}
END {
instrucciones
}
Algunos ejemplos:
# Ciclo 1 (while)
i=0
# Ciclo 2 (until)
i=0
until i == list.size do
print "#{list[i]} "
i += 1
end
# Ciclo 3 (for)
for x in list do
print "#{x} "
end
# Ciclo 4 (loop)
i=0
n=list.size-1
loop do
print "#{list[i]} "
i += 1
break if i > n
end
# Ciclo 6 (loop)
i=0
n=list.size-1
loop do
print "#{list[i]} "
i += 1
break unless i <= n
end
# Ciclo 7 (for)
n=list.size-1
for
i in 0..n do
print "#{list[i]} "
end
---
car = "Patriot"
--
calif = 70
puts result
--
for j in 1..5 do
for i in 1..5 do
print i, " "
end
puts
end
--
for i in 1..8 do
puts i
end
--
Ejemplo:
La manera más simple de leer una cadena en Ruby es ocupando la función gets:
Clases
Ejemplos de clases:
• automóvil,
• persona,
• libro,
• revista,
• reloj,
• silla,
• ...
Objetos e instancias
Def. Objeto. Un objeto es una instancia de una clase. Puede ser identificado
en forma única por su nombre y define un estado, el cuál es representado por los
valores de sus atributos en un momento en particular [3].
Instanciación
Los objetos pueden ser creados de la misma forma que una estructura de
datos:
Clases en C++
Sintaxis:
class <nombre_clase> {
<cuerpo de la clase>
};
Ejemplo:
class cEjemplo1 {
int x;
float y;
void fun(int a, float b) {
x=a;
y=b;
}
};
Una clase está formada por un conjunto de miembros que pueden ser datos,
funciones, clases anidadas, enumeraciones, tipos de dato, etc. Por el momento nos
vamos a centrar en los datos y las funciones (atributos y métodos).
Ejemplo:
class cEjemplo2{
int i;
int i; //error
int j;
int func(int, int);
};
Atributos miembro
Todos los atributos que forman parte de una clase deben ser declarados
dentro de la misma.
Métodos miembro
Los métodos al igual que los atributos, deber ser definidos en la clase, pero
el cuerpo de la función puede ir dentro o fuera de la clase. Si un método se
declara completo dentro de la clase, se considera como inline.
16
Aunque existe el concepto de sobrecarga que se verá más adelante
Carlos Alberto Fernández y Fernández
- 122 -
Programación Orientada a Objetos
con C++, Java y Ruby
inicial de esta sección, pero ahora con el cuerpo de un método fuera del cuerpo de
la clase.
Ejemplo:
//código en ejemplo3.h
class cEjemplo3 {
public:
int x;
float y;
int funX(int a) {
x=a;
return x;
}
float funY(float);
};
Ejemplo:
//error en declaración de un método
class x{
public:
int a;
f();
};
Sintaxis:
public:
<definición de miembros>
Sintaxis:
private:
<definición de miembros>
Normalmente, los atributos de la clase deben ser privados; así como los
métodos que no sean necesarios externamente o que puedan conducir a un estado
inconsistente del objeto.17
Ejemplo:
//código en ejemplo3.h
class cFecha {
private:
int dia;
int mes;
int an;
public:
char setDia(int); //poner día
int getDia(); //devuelve día
char setMes(int);
17
Un estado inconsistente sería ocasionado por una modificación indebida de los datos, por ejemplo una modificación sin
validación.
Carlos Alberto Fernández y Fernández
- 125 -
Programación Orientada a Objetos
con C++, Java y Ruby
int getMes();
char setAn(int);
int getAn();
};
Hay que recordar que una de las características de los objetos es que cada
uno guarda un estado particular de acuerdo al valor de sus atributos18.
Un ejemplo completo:
#include <iostream>
using namespace std;
class cEjemplo3 {
public:
int i;
int j;
};
int main() {
cEjemplo3 e1;
cEjemplo3 e2;
18
A diferencia de la programación modular, donde cada módulo tiene un solo estado.
Carlos Alberto Fernández y Fernández
- 126 -
Programación Orientada a Objetos
con C++, Java y Ruby
e1.i=10;
e1.j=20;
e2.i=100;
e2.j=20;
cout<<e1.i<<endl;
cout<<e2.i<<endl;
return 0;
}
class cCola{
private:
int q[10];
int sloc, rloc;
public:
void ini() { //funci¢n en l¡nea
sloc=rloc=-1;
}
char set(int);
int get();
};
#include <iostream>
#include "cCola.h"
return 1;
}
int cCola::get(){
if(rloc==sloc)
cout<<"la cola esta vacia";
else {
rloc++;
return q[rloc];
}
}
int main(){
cCola a,b, *pCola= new cCola; //¢ *pCola=NULL y despu‚s
asignarle
a.ini();
b.ini();
pCola->ini();
a.set(1);
b.set(2);
pCola->set(3);
a.set(11);
b.set(22);
pCola->set(33);
cout<<a.get()<<endl;
cout<<a.get()<<endl;
cout<<b.get()<<endl;
cout<<b.get()<<endl;
cout<<pCola->get()<<endl;
cout<<pCola->get()<<endl;
delete pCola;
return 0;
}
Clases en Java
Sintaxis:
class <nombre_clase> {
<cuerpo de la clase>
}
Ejemplo19:
19
Algunos ejemplos como este no son programas completos, sino simples ejemplos de clases. Podrán ser
compilados pero no ejecutados directamente. Para que un programa corra debe contener o ser una clase
derivada de applet, o tener un método main.
Carlos Alberto Fernández y Fernández
- 129 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
class cEjemplo2{
int i;
int i; //error
int j;
int func(int, int){}
}
Atributos miembro
Todos los atributos que forman parte de una clase deben ser declarados
dentro de la misma.
tipo nombreAtributo;
Métodos miembro
Miembros públicos.
Sintaxis:
Miembros privados.
Sintaxis:
Ejemplo:
class Fecha {
private int dia;
private int mes, an;
En Java todos los objetos son creados dinámicamente, por lo que se necesita
reservar la memoria de estos en el momento en que se van a ocupar. El operador
de Java está basado también en el de C++ y es new.20
20
La instrucción new, ya había sido usada para reservar memoria a un arreglo, ya que estos son considerados
objetos.
Carlos Alberto Fernández y Fernández
- 132 -
Programación Orientada a Objetos
con C++, Java y Ruby
Sintaxis:
Un ejemplo completo:
public class Ejemplo3 {
public int i, j;
e1.i=10;
e1.j=20;
e3.i=100;
e3.j=20;
System.out.println(e1.i);
System.out.println(e3.i);
}
}
class Cola{
Carlos Alberto Fernández y Fernández
- 133 -
Programación Orientada a Objetos
con C++, Java y Ruby
b.ini();
pCola.ini();
a.set(1);
b.set(2);
pCola.set(3);
a.set(11);
b.set(22);
pCola.set(33);
System.out.println(a.get());
System.out.println(a.get());
System.out.println(b.get());
System.out.println(b.get());
System.out.println(pCola.get());
System.out.println(pCola.get());
}
}
Clases en Ruby
Sintaxis:
class <nombre_clase>
<cuerpo de la clase>
end
Ejemplo21:
class Ejemplo01
def fun a,b
x=a
y=b
end
end
21
Algunos ejemplos como este no son programas completos, sino simples ejemplos de clases. Ruby es un
lenguaje interpretado. No existe un método principal que inicie la ejecución. El interprete recibe una lista de
instrucciones y éste comienza ejecutando de la línea inicial hasta la última línea.
Carlos Alberto Fernández y Fernández
- 136 -
Programación Orientada a Objetos
con C++, Java y Ruby
Métodos miembro
Un método es una operación que pertenece a una clase. Los métodos son
muy importantes en Ruby. En Ruby no existen funciones, pues todo el código es
representad en métodos (asociados a objetos). Aunque Ruby permite definir
código como funciones en otros lenguajes, en realidad ese código es un método
asociado (por omisión) a un objeto.
En Ruby es posible que un método definido para una clase quede indefinido:
Por ejemplo:
class Foo
def foo
end
end
...
undef foo
Sintaxis:
Sintaxis:
Ejemplo:
class A
private
def metodo_privado
# codigo
end
end
Atributos miembro
Todos los atributos que forman parte de una clase deben ser declarados
dentro de la misma. En Ruby los atributos son llamasoa variables de instancia, y
no requieren ser declarados fuera de los métodos. Podemos usar variables de
instancia conforme se necesiten. Una variable de instancia debe llevar como
prefijo el símbolo @, por ejemplo:
@variableInstancia
Ejemplo:
class InstTest
def set_foo(n)
@foo = n
end
def set_bar(n)
@bar = n
end
end
Ejemplo:
class Usuario
attr_accessor :nombre
attr_accessor :apellidos
attr_reader :login
attr_writer :password
...
def muestra
@nombre+” “+@apellidos
end
end
10.succ # 11
"hola".upcase # "HOLA"
[2,1,5,3,4].sort # [1,2,3,4,5]
objeto.metodo
Sintaxis:
identificador = Clase.new
Un ejemplo completo:
class Ejemplo3
@i # no es necesario
@j # especificar los atributos
def unMetodo x,y
@i=x
@j=y
puts "El valor de i es " + @i.to_s
puts "El valor de j es " + @j.to_s
end
end
require "Ejemplo3"
# ó load "Ejemplo3.rb"
obj1 = Ejemplo3.new
obj2 = Ejemplo3.new
obj1.unMetodo 10,20
obj2.unMetodo 100, 20
class Cola
@q=[]
@sloc= @rloc=-1
def ini
@sloc= @rloc=-1
@q=[]
end
return true
end
def get
if @rloc == @sloc then
puts "La cola esta vacia"
return false
else
@rloc+=1
return @q[@rloc]
end
end
end
require "Cola"
a = Cola.new
b = Cola.new
a.ini
b.ini
a.set 1
b.set 2
a.set 11
b.set(22)
puts a.get
puts a.get
puts b.get
puts b.get()
a.get
Ejemplo:
class cMiClase{
public:
int otraFuncion();
};
int main () {
cMiClase cM;
cM.otraFuncion();
return 0;
}
Ejemplo:
class MiClase{
public void otraFuncion(){
System.out.println("Metodo de la clase MiClase");
}
}
Ejemplo:
class MiClase
public
def otraFuncion
puts "Metodo de la clase MiClase"
end
end
def miMain
cM= MiClase.new
cM.otraFuncion
end
miMain
Una razón para usarlo es querer tener acceso a algún atributo posiblemente
oculto por un parámetro del mismo nombre.
También puede ser usado para regresar el objeto a través del método, sin
necesidad de realizar una copia en un objeto temporal.
Ejemplo en C++:
Fecha Fecha::getFecha(){
return *this;
}
Ejemplo en Java:
class Fecha {
private int dia;
private int mes, an;
…
public Fecha getFecha(){
return this;
Carlos Alberto Fernández y Fernández
- 146 -
Programación Orientada a Objetos
con C++, Java y Ruby
}
…
}
Ejemplo:
class SelfEjemplo
@x=0
@y=0
def getSelfEjemplo
return self
end
attr_accessor :x, :y
end
#código de prueba
obj1= SelfEjemplo.new
obj1.x=10
puts obj1.x
obj1.y="YY"
puts obj1.y
obj2=obj1.getSelfEjemplo
puts obj2.x
obj1.y=123
puts obj1.y # despliega 123
puts obj2.y # despliega 123
Sobrecarga de operaciones
Ejemplo en C++:
class MiClase{
int x;
public:
void modifica() {
x++;
}
void modifica(int y){
x=y*y;
}
}
22
También conocida como homonimia.
Carlos Alberto Fernández y Fernández
- 148 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo 2 en C++:
//fuera de POO
#include <iostream>
using namespace std;
int main() {
cout<<"10 elevado al cuadrado: "<<cuadrado(10)<<endl;
cout<<"10.5 elevado al cuadrado: "<<cuadrado(10.5)<<endl;
return 0;
}
Ejemplo en Java:
class MiClase{
int x;
public void modifica() {
x++;
}
public void modifica(int y){
x=y*y;
}
}
Ejemplo en Ruby:
class MiClase
attr_reader :x
def modifica
@x+=1
end
def modifica y
@x=y*y
end
end
#prueba
mc=MiClase.new
puts mc.x
# mc.modifica -- Error pues se ha redefinido el método
mc.modifica 10
puts mc.x
Constructor
Ejemplo:
class Cola{
private:
int q[100];
int sloc, rloc;
public:
Cola( ); //constructor
void put(int);
int get( );
};
Constructor de Copia
Es útil agregar a todas las clases un constructor de copia que reciba como
parámetro un objeto de la clase y copie sus datos al nuevo objeto.
Sintaxis:
Ejemplo:
class Arr{
private:
int a[10];
public:
Arr(int x=0) {
for( int i=0; i<10; i++){
if (x==0)
x=rand();
a[i]=x;
}
}
int main(){
Arr a(5), b;
srand( time(NULL) );
a.set(0,1);
a.set(1,11);
cout<<a.get(0)<<endl;
cout<<a.get(1)<<endl;
b.set(0,2);
b.set(1,22);
cout<<b.get(0)<<endl;
cout<<b.get(1)<<endl;
Arr d(a);
cout<<d.get(0)<<endl;
cout<<d.get(1)<<endl;
return 0;
}
Destructor
Ejemplo:
class Cola{
private:
int q[100];
int sloc, rloc;
public:
Cola( ); //constructor
~Cola(); //destructor
void put(int);
int get( );
};
Cola::~Cola( ){
cout<<"cola destruida\n";
}
class Cola{
private:
int q[10], sloc, rloc;
char *nom;
public:
Cola(char *cad=NULL) { //funcion en linea
if(cad){ //cadena!=NULL
nom=new char[strlen(cad)+1];
strcpy(nom, cad);
}else
nom=NULL;
sloc=rloc=-1;
}
~Cola( ) {
if(nom){ //nom!=NULL
cout<<"Cola : "<<nom<<" destruida\n";
delete [] nom;
}
}
char set(int);
int get();
};
int main(){
delete pCola;
}
Constructor
Ejemplo:
public class Cola{
private int q[];
23
En C++ no existe el concepto de finalizador, sino el de destructor, porque su tarea primordial es liberar la
memoria ocupada por el objeto, cosa que no es necesario realizar en Java.
Carlos Alberto Fernández y Fernández
- 156 -
Programación Orientada a Objetos
con C++, Java y Ruby
Finalizador
24
No se ha mencionado el modificador protected. Este concepto se explicará una vez que se haya visto el
manejo de herencia.
Carlos Alberto Fernández y Fernández
- 157 -
Programación Orientada a Objetos
con C++, Java y Ruby
El finalizador puede ser llamado como un método normal, inclusive puede ser
sobrecargado, pero un finalizador con parámetros no puede ser ejecutado
automáticamente por la máquina virtual de Java. Se recomiendo evitar el definir
un finalizador con parámetros.
Inicializadores en Ruby
La explicación para esto es que las clases en Ruby son instancias de la clase
Class. Por cada clase definida, un objeto de tipo Class es creado y asignado a una
constante del nombre especificado en la declaración de la clase. Cuando el
método new es llamado (NombreClase.new) para crear un objeto, se ejecuta por
default el método new de Class, el cual ejecuta al método allocate para asignar la
memoria del objeto, y por último, el método initialize del nuevo objeto es
ejecutado.
Sintaxis
class NombreClase
def initialize [(lista de parámetros)]
<código>
end
...
end
…
obj = NombreClase.new [(parámetros)]
Ejemplo:
class Cola
def initialize
@sloc= @rloc=-1
@q=[]
end
...
end
Cada objeto tiene su propio estado, pero a veces es necesario tener valores
por clase y no por objeto. En esos casos se requiere tener atributos estáticos que
sean compartidos por todos los objetos de la clase.
Clase
(Estado de laclase)
Objeto 1
(Estadodel objeto)
Objeto 2
(Estadodel objeto)
Objeto n
(Estadodel objeto)
Ejemplo:
class Objeto{
private:
char nombre[10];
static int numObjetos;
public:
Objeto(char *cadena=NULL);
~Objeto();
};
Objeto::Objeto(char *cadena){
if(cadena!=NULL)
strcpy(nombre, cadena);
else
nombre=NULL;
numObjetos++;
}
Objeto::~Objeto(){
numObjetos--;
}
Los atributos estáticos deben de ser inicializados al igual que los atributos
constantes, fuera de la declaración de la clase. Por ejemplo:
int Clase::atributo=0; int const Clase::ATRCONST=50;
Ejemplo :
class Persona{
private:
public:
Persona(char *c=NULL){
if(c!=NULL){
nombre= new char[strlen(c)+1];
strcpy(nombre, c);
cout<<"Persona: "<<nombre<<endl;
}else{
nombre=NULL;
cout<<"Persona: "<<endl;
}
nPersonas++;
}
~Persona(){
cout<<"eliminando persona : "<<nombre<<endl;
if(nombre)
delete []nombre;
nPersonas--;
}
int Persona::nPersonas=0;
const int Persona::MAX=10;
int main() {
cout<<"Número de personas:
"<<Persona::getnPersonas()<<endl;
Persona per1;
cout<<"Máximo de personas: "<<Persona::getMax()<<endl;
cout<<"Número de personas: "
<<Persona::getnPersonas()<<endl;
Ejemplo:
public class Objeto{
private String nombre;
private static int numObjetos;
public Objeto(String cadena){
if(cadena.length()!=0)
nombre=cadena;
else
nombre="cadena por omision";
numObjetos++;
}
Objeto uno,dos;
uno= new Objeto("");
dos= new Objeto("Objeto dos");
System.out.println("Objetos: " +
uno.getNumObjetos());
System.out.println("Objetos: " +
dos.getNumObjetos());
}
}
Otro ejemplo :
//prueba de miembros estáticos
public class Persona{
private static int nPersonas=0;
private static final int MAX=10;
String nombre;
}
}
Atributos de clase
Métodos de clase
Los métodos de clase son definidos en Ruby usando como prefijo el nombre
de la clase o la palabra reservada self seguido de punto y el nombre del método de
clase. self se resuelve como el nombre de la clase en este caso, siendo un
comportamiento distinto a cuando es usado dentro de un método (self se resuelve
como el objeto en ejecución).
Ejemplo:
class Persona
@@nPersonas=0
@@MAX=100 # no es una constante
@nombre
def initialize nom
@nombre=nom
puts "Persona: " + @nombre if nom.size>0
@@nPersonas+=1
end
def self.getMax
return @@MAX
end
def Persona.getnPersonas
return @@nPersonas
end
end
#código principal
Sintaxis:
Sintaxis:
Declaración.
25
Ayuda a cumplir el principio del mínimo privilegio, donde se debe restringir al máximo el acceso a los
datos cuando este acceso estaría de sobra. [1]
Carlos Alberto Fernández y Fernández
- 168 -
Programación Orientada a Objetos
con C++, Java y Ruby
Un método puede ser declarado dos veces tan sólo con que la firma del
método difiera por el uso de const. Objetos constantes ejecutarán al método
definido con const, y objetos variables ejecutarán al método sin esta restricción.
De hecho, un objeto variable puede ejecutar el método no definido con const por
lo que si el objetivo del método es el mismo, y este no modifica al objeto (e.g.,
métodos tipo get) bastaría con definir al método una vez.26
Ejemplo:
#include <iostream>
#include <time.h>
#include <stdlib.h>
class Arr{
private:
int a[10];
public:
26
Además, declarar a los métodos get y otros métodos que no modifican al objeto con el calificador const es
una buena práctica de programación.
Carlos Alberto Fernández y Fernández
- 169 -
Programación Orientada a Objetos
con C++, Java y Ruby
Arr(int x=0) {
srand( time(NULL) );
for( int i=0; i<10; i++){
if (x==0)
x=rand()%100;
a[i]=x;
}
}
char set(int, int);
int get(int) const ;
int get(int);
};
int main(){
const Arr a(5),b;
Arr c;
Sintaxis:
final <clase> <lista de identificadores de objetos>;
Por ejemplo:
final Light aLight = new Light(); // variable local final
aLight.noOfWhatts = 100; //Ok. Cambio en el edo. del objeto
Ejemplo:
class Fecha {
private int dia;
private int mes, año;
public Fecha(){
dia=mes=1;
año=1900;
}
public boolean setDia(int d){
if (d >=1 && d<=31){
dia= d;
return true;
}
return false;
} //poner día
public int getDia() {
return dia;
} //devuelve día
public boolean setMes(int m){
if (m>=1 && m<=12){
mes=m;
return true;
}
return false;
}
public int getMes(){
return mes;
}
public boolean setAño(int a) {
if (a>=1900){
año=a;
return true;
}
return false;
}
public int getAño() {
return año;
}
}
f= new Fecha();
f.setDia(10);
f.setMes(3);
f.setAño(2001);
System.out.println(f.getDia()+"/"+f.getMes()+"/"+f.getAño(
));
f= new Fecha(); //Error: la variable f es final y no
puede ser reasignada
}
}
Ejemplo:
class Fecha
def initialize
@dia= @mes =1
@anio=1900
end
def setAnio a
if a>=1900
@anio=a
return true
end
return false
end
#Código de prueba
Fe.setDia 10
Fe.setMes 3
Fe.setAnio 2008
puts Fe.dia.to_s+"/"+Fe.mes.to_s+"/"+Fe.anio.to_s
# ó:
puts "#{Fe.dia}/#{Fe.mes}/#{Fe.anio}"
class <nombreClase> {
friend <tipo> <metodo>();
...
public:
...
};
class <nombreClase> {
friend <nombreClaseAmiga>;
...
public:
...
};
Ejemplo 1:
//Ejemplo de funcion amiga con acceso a miembros privados
#include <iostream>
class ClaseX{
friend void setX(ClaseX &, int); //declaración friend
public:
ClaseX(){
x=0;
}
void print() const {
cout<<x<<endl;
}
private:
int x;
};
int main(){
ClaseX pr;
Ejemplo 2:
class Linea;
class Recuadro {
friend int mismoColor(Linea, Recuadro);
private:
int color; //color del recuadro
int xsup, ysup; //esquina superior izquierda
int xinf, yinf; //esquina inferior derecha
public:
void ponColor(int);
void definirRecuadro(int, int, int, int);
};
class Linea{
friend int mismoColor(Linea, Recuadro);
private:
int color;
int xInicial, yInicial;
int lon;
public:
void ponColor(int);
void definirLinea(int, int, int);
};
lon=l;
}
int main(){
Recuadro r;
Linea l;
l.definirLinea(2, 2, 10);
l.ponColor(4);
if(!mismoColor(l, r))
cout<<"No tienen el mismo color"<<endl;
if(mismoColor(l, r))
cout<<"Tienen el mismo color";
return 0;
}
Algunas restricciones:
. .* :: ?: sizeof
Ejemplo:
//programa de ejemplo de sobrecarga de operadores.
class Punto {
float x, y;
public:
Punto(float xx=0, float yy=0){
x=xx;
y=yy;
}
float magnitud();
Punto operator =(Punto);
Punto operator +(Punto);
Punto operator -();
Punto operator *(float);
Punto operator *=(float);
Punto operator ++(); //prefijo
Punto operator ++(int); //posfijo
// incremento prefijo
Punto Punto::operator ++(){
x++;
y++;
return *this;
}
// incremento posfijo
Punto Punto::operator++(int)
{
Punto temp= *this;
x++;
y++;
return temp;
}
int main(){
Punto a(1,1);
Punto b;
Punto c;
b++;
++b;
c=b;
c=a+b;
c=-a;
c=a*.5;
return 0;
}
Ejercicio : Crear una clase String para el manejo de cadenas. Tendrá dos
atributos: apuntador a carácter y un entero tam, para almacenar el tamaño de la
cadena. Sobrecargar operadores = (asignación) e (==) igualdad. Usar un
programa de prueba.
La estructura será la siguiente:
class String{
char *s;
int tam;
public:
String(char *=NULL);
String(const String &copia); //constructor de copia
~String();
//sobrecarga de constructor de asignación
const String &operator =(const String &);
//igualdad
int operator ==(const String &) const ;
};
Véase que es posible asignar una cadena " " sin sobrecargar el operador de
asignación, o comparar un objeto String con una cadena. Esto se logra gracias a
que se provee de un constructor que convierte una cadena a un objeto String. De
esta manera, este constructor de conversión es llamado automáticamente, creando
un objeto temporal para ser comparado con el otro objeto.
class String{
//operadores de inserción y extracción de flujo
friend ostream &operator << (ostream &, const String &);
friend istream &operator >> (istream &, String &);
private:
char *s;
int tam;
public:
String(char * =NULL);
//igualdad
int operator ==(const String &) const ;
//concatenación
String operator +(const String &);
//concatenación y asignación
const String &operator +=(const String &);
String::String(char *c){
if(c==NULL){
s=NULL;
tam=0;
} else {
tam=strlen(c);
s= new char[tam+1];
strcpy(s, c);
}
}
return s[i];
return s[0];
}
int main(){
String a("AAA");
String b("Prueba de cadena");
String c(b);
/*es un error hacer una asignación sin liberar memoria.
ese es el principal peligro de usar el operador
sobrecargado por default de asignación*/
a=b;
b.copia("H o l a");
b=c+c;
b="nueva";
c+=c;
String d("nueva cadena");
d+="Hola";
String e;
e=d+"Adios";
d="coche";
int x=0;
x=d=="coche"; //Lo contrario no es válido "coche"==d
char ch;
ch=d[7];
d[2]=’X’;
cout<<d<<endl;
cout<<"Introduce dos cadenas:";
cin>>e>>d;
cout<<"Cadenas:\n";
cout<<e<<endl<<d;
return 0;
}
Sintaxis:
def <operador>
...
end
Ejemplo:
def + op
return Punto.new(@x+op.x, @y+op.y)
end
def - (op)
Punto.new(@x-op.x, @y-op.y)
end
Carlos Alberto Fernández y Fernández
- 191 -
Programación Orientada a Objetos
con C++, Java y Ruby
def * (f)
temp=Punto.new @x*f, @y*f
return temp
end
def prueba
a= Punto.new 1,1
b= Punto.new
c= Punto.new
puts a.x
puts b.x
puts c.x
c=a+b
puts c.x
puts c.y
c+=a
puts c.x
puts c.y
c=a*0.5
puts c.x
puts c.y
end
prueba
Herencia en C++
Introducción
Generalización. Una clase base o superclase se dice que es más general que
la clase derivada o subclase.
Implementación en C++
Sintaxis general:
Ejemplo:
//ejemplo 01 de herencia
#include <iostream>
class Vehiculo{
int ruedas;
int pasajeros;
public:
void setRuedas(int);
int getRuedas();
void setPasajeros(int);
int getPasajeros();
};
int Vehiculo::getRuedas(){
return ruedas;
}
int Vehiculo::getPasajeros(){
return pasajeros;
}
void Camion::muestra(){
cout<<"Ruedas: "<< getRuedas()<<endl;
cout<<"Pasajeros: "<< getPasajeros()<<endl;
int main(){
Camion ford;
ford.setRuedas(6);
ford.setPasajeros(3);
ford.setCarga(3200);
ford.muestra();
return 0;
}
Tipo de Descripción
acceso
private Un miembro privado únicamente puede ser utilizado por
los métodos miembro y funciones amigas27 de la clase
donde fue declarado.
protected Un miembro protegido puede ser utilizado únicamente
por los métodos miembro y funciones amigas de la clase
donde fue declarado o por los métodos miembro y
funciones amigas de las clases derivadas.
27
Funciones amiga es un tema que se verá más adelante.
Carlos Alberto Fernández y Fernández
- 196 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
//ejemplo de control de acceso
class S{
char *f1();
int a;
protected:
int b;
int f2();
private:
int c;
int f3();
public:
int d, f;
char *f4(int);
};
int main(){
S obj;
obj.f1(); //error
obj.a=1; //error
obj.f2();//error
obj.b=2; //error
obj.c=3; //error
obj.f3(); //error
obj.d=5;
obj.f4(obj.f);
return 0;
}
Ejemplo:
//ejemplo de control de acceso en herencia
class Base{
int a;
protected:
int b;
public:
int c;
};
void Derivada::g(){
a=0; //error, es privado
b=1; //correcto, es protegido
c=2; //correcto, es público
}
Para accesar a los miembros de una clase base desde una clase derivada, se
pueden ajustar los permisos por medio de un calificador public, private o
protected.
Si una clase base es declarada como pública de una clase derivada, los
miembros públicos y protegidos son accesibles desde la clase derivada, no así los
miembros privados.
Si una clase base es declarada como privada de otra clase derivada, los
miembros públicos y protegidos de la clase base serán miembros privados de la
clase derivada. Los miembros privados de la clase base permanecen inaccesibles.
Ejemplo de sintaxis:
class base {
...
};
class x{
public:
F();
};
void g( y *p){
p->f(); //error
}
Ejemplo:
class X{
protected:
int i;
int j;
public:
void preg_ij();
void pon_ij();
};
void X::preg_ij() {
cout<< "Escriba dos números: ";
cin>>i>>j;
}
void X::pon_ij() {
cout<<i<<' '<<j<<endl;
}
public:
int preg_k();
void hacer_k();
};
void Y::hacer_k() {
k=i*j;
}
var.preg_ij();
var.pon_ij();
var.hacer_k();
cout<<var.preg_k()<<endl;
var2.f();
var2.pon_ij();
return 0;
}
Ejemplo :
// POINT.H
// clase Point
#ifndef POINT_H_
#define POINT_H_
class Point {
friend ostream &operator<<(ostream &, const Point &);
public:
Point(float = 0, float = 0);
void setPoint(float, float);
float getX() const { return x; }
float getY() const { return y; }
protected:
float x, y;
};
#endif /*POINT_H_*/
// POINT.CPP
#include <iostream>
#include "point.h"
return output;
}
// CIRCLE.H
// clase Circle
#ifndef CIRCLE_H
#define CIRCLE_H
#include <iostream>
#include <iomanip.h>
#include "point.h"
void setRadius(float);
float getRadius() const;
float area() const;
protected:
float radius;
};
#endif /*CIRCLE_H_*/
// CIRCLE.CPP
#include "circle.h"
// salida en el formato:
// Center = [x, y]; Radius = #.##
return output;
}
//Prueba.cpp
// Probando apuntadores a clase base a apuntadores a clase
derivada
#include <iostream>
#include <iomanip.h>
#include "point.h"
#include "circle.h"
int main(){
Point *pointPtr, p(3.5, 5.3);
Circle *circlePtr, c(2.7, 1.2, 8.9);
cout << "Point p: " << p << "\nCircle c: " << c << endl;
return 0;
}
Sintaxis:
Ejemplo:
// POINT.H
#ifndef POINT_H
#define POINT_H
class Point {
public:
Point(float = 0.0, float = 0.0);
~Point();
protected:
float x, y;
};
#endif /*POINT_H_*/
// POINT.CPP
#include <iostream>
#include "point.h"
using namespace std;
Point::Point(float a, float b){
x = a;
y = b;
Point::~Point(){
cout << "Destructor Point: "
<< '[' << x << ", " << y << ']' << endl;
}
// CIRCLE.H
#ifndef CIRCLE_H
#define CIRCLE_H
#include "point.h"
#endif /*CIRCLE_H_*/
// CIRCLE.CPP
#include "circle.h"
Circle::~Circle(){
cout << "Destructor Circle: radio es "
<< radius << " [" << x << ", " << y << ']' << endl;
}
// Main.CPP
#include <iostream.h>
#include "point.h"
#include "circle.h"
int main(){
// Muestra llamada a constructor y destructor de Point
{
Point p(1.1, 2.2);
}
Ejemplo :
// EMPLOY.H
#ifndef EMPLOY_H
#define EMPLOY_H
class Employee {
public:
Employee(const char*, const char*);
void print() const;
~Employee();
private:
char *firstName;
char *lastName;
};
28
En teoría esto no debería ser necesario anular operaciones si nos apegamos a la regla del 100% (de
conformidad con la definición)
Carlos Alberto Fernández y Fernández
- 209 -
Programación Orientada a Objetos
con C++, Java y Ruby
#endif /*EMPLOY_H_*/
// EMPLOY.CPP
#include <string.h>
#include <iostream>
#include <assert.h>
#include "employ.h"
Employee::~Employee(){
delete [] firstName;
delete [] lastName;
}
// HOURLY.H
#ifndef HOURLY_H
#define HOURLY_H
#include "employ.h"
};
#endif /*HOURLY_H_*/
// HOURLY_B.CPP
#include <iostream>
#include <iomanip.h>
#include "hourly.h"
// main.CPP
#include <iostream>
#include "hourly.h"
int main(){
HourlyWorker h("Bob", "Smith", 40.0, 7.50);
h.print();
return 0;
}
Una clase puede heredar miembros de más de una clase; lo que se conoce
como herencia múltiple.
Sintaxis:
Ejemplo:
class A{
public:
int i;
void a(){}
};
class B{
public:
int j;
void b(){}
};
class C{
public:
int k;
void c(){}
};
int main() {
D var1;
var1.a();
var1.b();
var1.c();
var1.d();
return 0;
}
Otro ejemplo :
// BASE1.H
#ifndef BASE1_H
#define BASE1_H
class Base1 {
public:
Base1(int x) { value = x; }
int getData() const { return value; }
protected:
int value;
};
#endif /*BASE1_H_*/
// BASE2.H
#ifndef BASE2_H
#define BASE2_H
class Base2 {
public:
Base2(char c) { letter = c; }
char getData() const { return letter; }
protected:
char letter;
};
#endif /*BASE2_H_*/
// DERIVED.H
#ifndef DERIVED_H
#define DERIVED_H
// herencia múltiple
class Derived : public Base1, public Base2 {
friend ostream &operator<<(ostream &, const Derived &);
public:
Derived(int, char, float);
float getReal() const;
private:
float real;
};
#endif /*DERIVED_H_*/
// DERIVED.CPP
#include <iostream.h>
#include "base1.h"
#include "base2.h"
#include "derived.h"
return output;
}
// main.CPP
#include <iostream.h>
#include "base1.h"
#include "base2.h"
#include "derived.h"
int main(){
Base1 b1(10), *base1Ptr; Base2 b2('Z'), *base2Ptr;
Derived d(7, 'A', 3.5);
cout << "Objeto b1 contiene entero "
<< b1.getData()
<< "\nObjeto b2 contiene caracter "
<< b2.getData()
<< "\nObjeto d contiene:\n" << d;
cout << "\n\nmiembros de clase derivada pueden ser"
<< " accesados individualmente:"
<< "\n Entero: " << d.Base1::getData()
<< "\n Caracter: " << d.Base2::getData()
<< "\n Número real: " << d.getReal() << "\n\n";
// Probar: cout<<d.getData(); Es un error?
cout << "Miembros derivados pueden ser tratados como "
<< "objetos de su clase base:\n";
base1Ptr = &d;
cout << "base1Ptr->getData() "
<< base1Ptr->getData();
base2Ptr = &d;
Ejemplo:
void f( D *p) {
p->b=0; //ambiguo
}
int main(){
D obj;
f(&obj);
return 0;
}
class A{
public:
int next;
};
class B: public A{
};
class C: public A{
};
int D::g(){
class E: public D{
public:
int x;
int getx(){
return x;
}
};
int main(){
D obj;
E obje;
obj.B::next=10;
obj.C::next=20;
// obj.A::next=11; Error: acceso ambiguo
// obj.next=22; Error: acceso ambiguo
cout<<"next de B: "<<obj.B::next<<endl;
cout<<"next de C: "<<obj.C::next<<endl;
obje.x=0;
obje.B::next=11;
obje.C::next=22;
cout<<"obje next de B: "<<obje.B::next<<endl;
cout<<"obje next de C: "<<obje.C::next<<endl;
return 0;
}
Este programa hace que las instancias de la clase D tengan objetos de clase
base duplicados y provoca los accesos ambiguos. Este problema se resuelve con
herencia virtual.
El acceso entonces a los miembros puede hacerse usando una de las clases
de las cuales heredo el miembro:
obj.B::next=10;
obj.C::next=20;
obj.next=22;
En cualquier caso se tiene solo una copia del miembro, por lo que cualquier
modificación del atributo next es sobre una única copia del mismo.
Sintaxis general:
<Constructor clase derivada>(<argumentos> : <base1>
(<argumentos>), <base2> (<argumentos>), ... , <basen>
(<argumentos>) {
...
}
Herencia en Java
Implementación en Java
Sintaxis general:
Ejemplo:
//ejemplo de herencia
class Vehiculo{
private int ruedas;
private int pasajeros;
ford.muestra();
}
BlueJ
/**
* Write a description of class Vehiculo here.
*
* @author (your name)
* @version (a version number or a date)
*/
public class Vehiculo
{
// instance variables - replace the example below with
your own
private int x;
/**
* Constructor for objects of class Vehiculo
*/
public Vehiculo()
{
// initialise instance variables
x = 0;
}
/**
* An example of a method - replace this comment with your
own
*
* @param y a sample parameter for a method
* @return the sum of x and y
*/
public int sampleMethod(int y)
{
// put your code here
return x + y;
}
}
/**
* Write a description of class Camion here.
*
* @author (your name)
* @version (a version number or a date)
*/
public class Camion extends Vehiculo
{
// instance variables - replace the example below with
your own
private int x;
/**
* Constructor for objects of class Camion
*/
public Camion()
{
// initialise instance variables
x = 0;
}
/**
* An example of a method - replace this comment with your
own
*
* @param y a sample parameter for a method
* @return the sum of x and y
*/
public int sampleMethod(int y)
{
// put your code here
return x + y;
}
}
Clase Object
En Java toda clase que se define tiene herencia implícita de una clase
llamada object. En caso de que la clase que crea el programador defina una
herencia explícita a una clase, hereda las características de la clase Object de
manera indirecta29.
Class Object
java.lang.Object
Constructor Summary
Object()
Method Summary
protected clone()
Object
Creates and returns a copy of this object.
boolean equals(Object obj)
Indicates whether some other object is "equal to" this one.
29
En este caso hay quye considerar que las características de la clase Object pudieron haber sido modificadas
a través de la jerarquía de herencia.
30
Tomada de la documentación del jdk 1.6
Carlos Alberto Fernández y Fernández
- 226 -
Programación Orientada a Objetos
con C++, Java y Ruby
protected finalize()
void
Called by the garbage collector on an object when garbage
collection determines that there are no more references to the object.
Class<?> getClass()
Returns the runtime class of an object.
int hashCode()
Returns a hash code value for the object.
void notify()
Wakes up a single thread that is waiting on this object's monitor.
void notifyAll()
Wakes up all threads that are waiting on this object's monitor.
String toString()
Returns a string representation of the object.
void wait()
Causes current thread to wait until another thread invokes the
notify() method or the notifyAll() method for this object.
void wait(long timeout)
Causes current thread to wait until either another thread invokes
the notify() method or the notifyAll() method for this object, or a
specified amount of time has elapsed.
void wait(long timeout, int nanos)
Causes current thread to wait until another thread invokes the
notify() method or the notifyAll() method for this object, or some other
thread interrupts the current thread, or a certain amount of real time has
elapsed.
Tipo de Descripción
acceso
private Un miembro privado únicamente puede ser utilizado por
los métodos miembro de la clase donde fue declarado.
Un miembro privado no es posible que sea manejado ni
siquiera en sus subclases.
protected Un miembro protegido puede ser utilizado únicamente
por los métodos miembro de la clase donde fue
declarado, por los métodos miembro de las clases
derivadas ó clases que pertenecen al mismo paquete.
El acceso protegido es como un nivel intermedio entre el
acceso privado y público.
public Un miembro público puede ser utilizado por cualquier
método. Este es visible en cualquier lugar que la clase
sea visible
Ejemplo:
//ejemplo de control de acceso
class Acceso{
protected int b;
protected int f2() {
return b;
}
private int c;
private int f3() {
return c;
}
public int d, f;
public int f4(){
return d;
}
obj.d=5;
obj.f4();
}
}
Este controlador de acceso public, opera a nivel de la clase para que esta se
vuelva visible y accesible desde cualquier lugar, lo que permitiría a cualquier otra
clase hacer uso de los miembros de la clase pública.
// definición de la clase
La omisión de este calificador limita el acceso a la clase para que solo sea
utilizada por clases pertenecientes al mismo paquete.
Constructores de superclase
Ejemplo:
Superclase s= new superclase(), aptSuper;
Subclase sub= new subclase(), aptSub;
//válido
aptSuper = sub;
//inválido
aptSub= (Subclase) s;
// constructor
public Point( double a, double b ) {
setPoint( a, b );
}
// obtiene coordenada x
public double getX() {
return x;
}
// obtiene coordenada y
public double getY() {
return y;
}
// Constructor
public Circle( double r, double a, double b ) {
super( a, b ); // llamada a constructor de clase base
setRadius( r );
}
Redefinición de métodos
Ejemplo:
//clase empleado
public class Empleado {
//clase TrabajadorporHora
public class TrabajadorPorHora extends Empleado {
private float wage, hours;
public TrabajadorPorHora(String first, String last, float
initHours, float initWage) {
super(first, last);
hours = initHours;
wage = initWage;
}
Calificador final
//definición de la clase
}
De esta forma, la clase no permite generar subclases a partir de ella. De
hecho, el API de Java incluye muchas clases final, por ejemplo la clase
java.lang.String no puede ser especializada.
Interfaces
Una interfaz tiene un formato muy similar a una clase, sus principales
características:
• Una clase puede implementar varias interfaces, aunque solo pueda heredar
una clase.
31
En esta caso si se considera la declaración de prototipos.
Carlos Alberto Fernández y Fernández
- 238 -
Programación Orientada a Objetos
con C++, Java y Ruby
//definición de la clase
//debe incluirse la definición de los métodos de la
interfaz
//con la implementación del código de dichos métodos.
}
Además, una interfaz puede ser extendida de la misma forma que una clase,
aprovechando las interfaces previamente definidas, mediante el uso de la claúsula
extends.
[public] interface <nombreInterfaz> extends <InterfazBase> {
//descripción de miembros
Ejemplo:
//interfaz
interface IStack {
void push(Object item);
32
El parámetro debe incluir el nombre, el cual no es obligatorio que coincida en la implementación.
Carlos Alberto Fernández y Fernández
- 239 -
Programación Orientada a Objetos
con C++, Java y Ruby
Object pop();
}
safeStackRef.push("Dolar");
stackRef.push("Peso");
System.out.println(isafeStackRef.pop());
System.out.println(istackRef.pop());
System.out.println(objRef.getClass());
}
}
<<Interface>>
IStack Object
push()
pop()
StackImpl
push()
pop()
SafeStack
isFull()
isEmpty()
Por otro lado, una interfaz tambien puede ser utilizada para definir nuevos
tipos. Una interfaz así o una clase que implementa a una interfaz de este estilo es
conocida como Supertipo.
Herencia en Ruby
Implementación en Ruby
Ruby, al igual que Java, no cuenta con herencia múltiple, por lo que
únicamente es posible indicar una clase como superclase. Para esto se utiliza el
símbolo < antes del nombre de la superclase.
Sintaxis:
Ejemplo:
Retomando el ejemplo del la jerarquía de Vehículo y Camión, visto en la sección
de herencia en Java.
# ejemplo de herencia
class Vehiculo
@ruedas
@pasajeros
attr_accessor :ruedas, :pasajeros
end
public
def muestra
# uso de métodos heredados y generados automaticamente
por attr_accessor
puts "Ruedas: #{ruedas}"
# Código de prueba
ford= Camion.new
ford.ruedas =6
ford.pasajeros=3
ford.carga=3200
ford.muestra
Clase Class
Las clases en Ruby son considerados objetos de primera clase33. Cada clase
declarada en Ruby es una instancia de la clase Class [12].
class methods
inherited aClass.inherited( aSubClass )
This is a singleton method (per class) invoked by Ruby when a subclass of
aClass is created. The new subclass is passed as a parameter.
class Top
def Top.inherited(sub)
print "New subclass: ", sub, "\n"
end
33
Pueden ser usados en el lengauje de programación como cualquier otro objeto.
34
De hecho, el método new de la clase Class puede ser redefinido, aunque no es una práctica recomendada.
Carlos Alberto Fernández y Fernández
- 244 -
Programación Orientada a Objetos
con C++, Java y Ruby
end
produces:
instance methods
new aClass.new( [ args ]* ) -> anObject
Creates a new object of aClass's class, then invokes that object's initialize
method, passing it args.
Class.superclass » Module
Object.superclass » nil
Clase Object
La clase padre de todas las clases en Ruby es la clase Object, por lo que sus
métodos están disponibles para todos los objetos a menos que estos se encuentren
redefinidos.
Tipo de Descripción
acceso
private Un método privado bo puede ser llamado mediante un
objeto. Por esta razón, los métodos privados solo pueden
ser utilizados en la definición de la clase.
protected Un método protegido puede ser utilizado únicamente
por objetos de la clase donde se define el método, asi
como por sus subclases.
public Un método público puede ser utilizado por cualquier
método. Este es visible en cualquier lugar que la clase
sea visible. Los métodos son públicos por omisión, con
excepción del método initialize, el cual es privado.
Carlos Alberto Fernández y Fernández
- 246 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
class MiClase
ó:
class MiClase
def metodo1
end
...
Inicializadores de superclase
Ejemplo:
class Persona
end
# ...
end
Ejemplo:
protected
@x
@y # coordenadas del punto
# constructor
def initialize a, b
setPoint a, b
end
@radius
# Constructor
def initialize r, a, b
super a, b # llamada a constructor de clase base
setRadius r
end
def prueba
p = Point.new 3.5, 5.3
c = Circle.new 2.7, 1.2, 8.9
end
prueba
Redefinición de métodos
Ejemplo:
#clase empleado
class Empleado
@firstName
@lastName
def print
puts @firstName.to_s + " " + @lastName.to_s
end
end
#clase TrabajadorporHora
class TrabajadorPorHora < Empleado
@wage
@hours
def getPay
@wage * @hours
end
def print
puts "Metodo print de Trabajador por hora"
puts " es un trabajador por hora con sueldo de" +" $"
+ getPay.to_s
end
end
#prueba de clases
e= Empleado.new "nombre", "apellido"
Módulos
module <nombre-módulo>
<código>
end
nombre-módulo::método
Mixins
class unaClase
include <nombre-módulo>
...
end
Ejemplo:
#modulo
module Stack
def push(item) end
def pop; end
end
35
“For a real ice cream treat, try _Steve's Ice Cream_ (191 Elm Street, Sommerville). Steve's homemade ice
cream is perhaps the best in town. Cones are $.35 and $.55, and for $.10 each you can choose "mix-ins,"
consisting of M&M's, Heath bars, and many others. If you want fruit mixed in it costs $.10 more. Sundaes
are $.75 and $1.25, banana splits are $1.75, and egg creams are $.40. The portions at Steve's are large, and
so are the lines, so expect to do a little waiting. It's worth it.” [14] pág. 224
Carlos Alberto Fernández y Fernández
- 255 -
Programación Orientada a Objetos
con C++, Java y Ruby
@stackArray
@tos
public
def initialize
@stackArray = []
@tos = -1
end
@stackArray[@tos+=1] = item
end
def peek
return @stackArray[@tos]
end
end
end
def isFull
end
end
def initialize
super
end
def stackUser
safeStackRef = SafeStackImpl.new
safeStackRef.push("Dolar");
safeStackRef.push "Peso"
puts safeStackRef.pop
puts safeStackRef.pop
puts safeStackRef.class
end
stackUser
Una clase puede estar relacionada con otra clase, o en la práctica un objeto
con otro objeto.
Ejemplo:
Profesor Cubículo
Asociación
36
El término de relación es usado muchas veces como sinónimo de asociación, debido a que el concepto
surge de las relaciones en bases de datos relacionales. Sin embargo el término más apropiado es el de
asociación, ya que existen en objetos otros tipos de relaciones, como la relación de agregación y la de
herencia.
Carlos Alberto Fernández y Fernández
- 259 -
Programación Orientada a Objetos
con C++, Java y Ruby
B *pB;
};
class B{
//lista de atributos
A *pA;
};
dejar accesos a áreas de memoria no permitidas o dejar objetos "volando", sin que
nadie haga referencia a ellos.
Si una clase mantiene una asociación consigo misma se dice que es una
asociación reflexiva.
Ejemplo: Persona puede tener relaciones entre si, si lo que nos interesa es
representar a las personas que guardan una relación entre sí, por ejemplo si son
parientes. Es decir, un objeto mantiene una relación con otro objeto de la misma
clase.
Persona
Asociación reflexiva
"uno a uno": donde dos objetos se relacionan de forma exclusiva, uno con el
otro.
Ejemplo:
Uno: Un alumno tiene una boleta de calificaciones.
Uno: Una boleta de calificaciones pertenece a un alumno.
"uno a muchos": donde uno de los objetos puede estar relacionado con
muchos otros objetos.
Ejemplo:
Uno: un libro solo puede estar prestado a un alumno.
Muchos: Un usuario de la biblioteca puede tener muchos libros
prestados.
"muchos a muchos": donde cada objeto de cada clase puede estar relacionado
con muchos otros objetos.
Ejemplo:
Muchos: Un libro puede tener varios autores.
Muchos: Un autor puede tener varios libros.
Departamento
1 1
* *
Empleo * * Proyecto
class A{
...
B *pB;
};
class B{
A *p[5];
//ó
A **p;
}
Persona
Compañía
Persona
Persona
Compañía
Persona
Ejemplo:
Se muestra un código simplificado para manejo de asociaciones.
Clase Libro
#ifndef LIBRO_H_
#define LIBRO_H_
class Persona;
class Libro {
public:
char nombre[10];
Persona *pPersona;
Libro();
~Libro();
};
#endif /*LIBRO_H_*/
#include <iostream>
#include "Persona.h"
#include "Libro.h"
Libro::Libro(){
nombre[0]='\0';
pPersona=NULL;
}
Libro::~Libro(){
if(pPersona!=NULL)
for(int i=0; i<5; i++)
if (pPersona->pLibrosPres[i]==this)
pPersona->pLibrosPres[i]=NULL;
Clase Persona
#ifndef PERSONA_H_
#define PERSONA_H_
class Libro;
class Persona {
public:
Libro *pLibrosPres[5];
Persona();
~Persona();
};
#endif /*PERSONA_H_*/
#include <iostream>
#include "Libro.h"
#include "Persona.h"
Persona::Persona(){
int i;
Persona::~Persona(){
int i;
for(i=0; i<5; i++)
if(pLibrosPres[i]!=NULL)
pLibrosPres[i]->pPersona=NULL;
}
B pB;
}
class B{
//lista de atributos
A pA;
}
Ejemplo:
class A{
//lista de atributos
B pB;
}
class B{
//lista de atributos
}
class A{
...
B pB;
}
class B{
A p[];
}
Al igual que en C++, es posible manejar una clase independiente que agrupe
a pares de direcciones en un objeto independiente de la clase37. Por ejemplo, en
una estructura de lista.
Ejemplo:
Se muestra un código simplificado para manejo de asociaciones.
//clase Libro
class Libro {
private String nombreLibro;
public Alumno pAlumno;
public Libro(){
//al momento de crearse la instancia, no existe
// relación con ningún Alumno
pAlumno=null;
}
37
Ver figura en tema correspondiente de C++
Carlos Alberto Fernández y Fernández
- 268 -
Programación Orientada a Objetos
con C++, Java y Ruby
//clase Alumno
class Alumno {
public Libro pLibrosPres[];
public Alumno(){
int i;
//se asume una multiplicidad de 5
pLibrosPres = new Libro[5]
for(i=0; i<5; i++)
pLibrosPres[i]=null;
}
class Libro {
private String nombreLibro;
private String clave;
public Alumno pAlumno;
public Libro(){ }
protected finalize {}
}
class B
#lista de atributos
@pA
end
Ejemplo:
class A
#lista de atributos
@pB
end
class B
#lista de atributos
end
Dicho concepto implica obviamente cierta dependencia entre los objetos, por
lo que hay que tener en cuenta que pasa con los objetos que son parte del objeto
compuesto cuando éste último se destruye. En general tenemos dos opciones:
Por el momento vamos a considerar la segunda opción, por ser más fácil de
implementar y porque es la acción natural de los objetos que se encuentran
embebidos como un atributo más en una clase.
Ejemplo:
class Nombre {
private:
char paterno[20],
materno[20],
nom[15];
public:
set(char *, char*, char *);
...
};
class Persona {
private:
int edad;
Nombre nombrePersona;
...
};
Sintaxis:
donde la lista de argumentos del objeto compuesto debe incluir a los argumentos
de los objetos componentes, para que puedan ser pasados en la creación del
objeto.
Ejemplo:
#include <iostream>
#include <string.h>
class Nombre {
char *nombre,
*paterno,
*materno;
public:
Nombre(char *n, char *p, char*m){
nombre=new char[strlen(n)+1];
paterno=new char[strlen(p)+1];
materno=new char[strlen(m)+1];
strcpy(nombre, n);
strcpy(paterno, p);
strcpy(materno, m);
}
~Nombre(){
cout<<"destructor de Nombre: "<<nombre<<endl;
delete []nombre;
delete []paterno;
delete []materno;
}
};
class Persona{
Nombre miNombre;
int edad;
public:
Persona(char *n, char *p, char*m): miNombre(n, p, m){
edad=0;
}
};
int main() {
Persona *per1;
per1= new Persona("uno", "dos", "tres");
Persona per2("Bob", "the", "builder");
delete per1;
return 0;
}
UMLGEC ++
38
Información básica sobre UML puede ser vista en [18].
Carlos Alberto Fernández y Fernández
- 277 -
Programación Orientada a Objetos
con C++, Java y Ruby
Al igual que en C++, vamos a considerar la segunda opción, por ser más
fácil de implementar y es la acción natural de los objetos que se encuentran
embebidos como un atributo más una clase.
Ejemplo:
class Nombre {
private String paterno;
private String materno;
private String nom;
class Persona {
private int edad;
private Nombre nombrePersona;
...
Ejemplo:
//Programa Persona
class Nombre {
private String nombre,
paterno,
materno;
public Nombre(String n, String p, String m){
nombre= new String(n);
paterno= new String(p);
materno= new String(m);
}
}
edad=0;
}
La agregación nos dice también que un objeto que es parte de otro objeto,
puede a su vez ser un objeto compuesto. [19]
39
Lo importante aquí es considerar en que solo existe la posibilidad de contener un objeto de si mismo. Si
esto fuera una condición obligatoria y no opcional, estaríamos definiendo un objeto infinito. Este problema
se ve reflejado en lenguajes como C++, donde la forma más simple de implementar la agregación es
definiendo un objeto al cual se le asigna espacio en tiempo de compilación, generando entonces el problema
de que cada objeto debe reservar memoria para sus componentes, por lo que el compilador no permite que de
esta manera se autocontenga. En Java esto no generaría problema porque implícitamente todos los atributos
que no son datos simples requieren de una asignación de memoria dinámica.
Carlos Alberto Fernández y Fernández
- 281 -
Programación Orientada a Objetos
con C++, Java y Ruby
year = yr;
day = checkDay( dy ); // validar el dia
// Clase Empleado
public class Employee {
private Employee e;
public EmployeeTest() {
e = new Employee( "Juanito", "Sanchez", 7, 24, 49,
3, 12, 88 );
}
Al igual que en C++ y Java, vamos a considerar la segunda opción, por ser
más fácil de implementar y es la acción natural de los objetos que se encuentran
embebidos como un atributo más una clase.
Ejemplo:
class Nombre
@paterno
@materno
@nom
class Persona
@edad
@nombrePersona
...
end
Ejemplo:
#Programa Persona
class Nombre
@nombre
@paterno
@materno
def initialize(nombre, paterno, materno)
@nombre= String.new nombre
@paterno= String.new paterno
@materno= String.new materno
end
end
class Persona
@miNombre
@edad
def initialize(n, p, m)
@miNombre = Nombre.new(n, p, m)
@edad =0
end
end
#código de prueba
per1= Persona.new("uno", "dos", "tres")
per2= Persona.new("mi nombre", "mi apellido", "otro apellido")
@month # 1-12
@day # 1-31 dependiendo del mes
@yea; # cualquier año
@year = yr;
@day = checkDay( dy ); # validar el dia
def to_s
return @month.to_s + "/" + @day.to_s + "/" + @year.to_s
end
end
# Clase Empleado
class Employee
@firstName
@lastName
@birthDate
@hireDate
def to_s
return @lastName + ", " + @firstName +
" Contratado: " + @hireDate.to_s +
" Fecha nacimiento: " + @birthDate.to_s
end
end
# clase EmployeeTest
class EmployeeTest
attr_reader :e
@e
def initialize
@e = Employee.new( "Juanito", "Sanchez", 7, 24, 49,
3, 12, 88 )
end
end
# codigo de prueba
et= EmployeeTest.new
puts et.e.to_s
Las funciones virtuales son muy especiales, debido a que cuando una
función es accesada por un apuntador a una clase base, y éste mantiene una
referencia a un objeto de una clase derivada, el programa determina en tiempo de
ejecución a que función llamar, de acuerdo al tipo de objeto al que se apunta.
Esto se conoce como ligadura tardía40 y el compilador de C++ incluye en el
código máquina el manejo de ese tipo de asociación de métodos.
40
Término opuesto a ligadura temprana o ligadura estática, la cual asocia los métodos en tiempo de
compilación.
Carlos Alberto Fernández y Fernández
- 289 -
Programación Orientada a Objetos
con C++, Java y Ruby
Sintaxis:
class base {
virtual <tipo> <método> (<parámetros);
};
Ejemplo:
class base {
public:
virtual void quien(){
cout<<"base\n";
}
};
cout<<"segunda\n";
}
};
int main() {
base objBase, *pBase;
primera obj1;
segunda obj2;
tercera obj3;
cuarta obj4;
pBase=&objBase;
pBase->quien();
pBase=&obj1;
pBase->quien();
pBase=&obj2;
pBase->quien();
pBase=&obj3;
pBase->quien();
pBase=&obj4;
pBase->quien();
return 0;
}
Hay que hacer notar que las funciones virtuales pueden seguirse usando sin
apuntadores, mediante un objeto de la clase. De esta forma, el método a ejecutar
se determina de manera estática; es decir, en tiempo de compilación (ligadura
estática). Obviamente el método a ejecutar es aquel definido en la clase del objeto
o el heredado de su clase base, si la clase derivada no lo redefinió.
Si se declara en una clase derivada un método con otro tipo de dato como
retorno, el compilador manda un error, ya que esto no es permitido.
Existen clases que son útiles para representar una estructura en particular,
pero que no van a tener la necesidad de generar objetos directamente a partir de
esa clase, estas se conocen como clases abtractas, o de manera más apropiada
como clases base abstractas, puesto que sirven para definir una estructura
jerarquica.
La clase base abstracta entonces, tiene como objetivo proporcionar una clase
base que ayude al modelado de la jerarquía de herencia, aunque esta sea muy
general y no sea práctico tener instancias de esa clase.
Por lo tanto, de una clase abstracta no se pueden tener objetos, mientras que
en clases a partir de las cuales se puedan instanciar objetos se conocen como
clases concretas.
Es importante tener en cuenta que una clase sigue siendo abstracta hasta que
no se implemente la función virtual pura, en una de las clases derivadas. Si no se
hace la implementación, la función se hereda como virtual pura y por lo tanto la
clase sigue siendo considerada como abstracta.
Polimorfismo
Destructores virtuales
class Employee {
public:
Employee(const char *, const char *);
~Employee();
const char *getFirstName() const;
const char *getLastName() const;
#endif /*EMPLEADO_H_*/
// EMPLEADO.CPP
#include <iostream>
#include <string>
#include <assert.h>
#include "empleado.h"
Employee::~Employee()
{
delete [] firstName;
delete [] lastName;
}
return firstName;
}
// JEFE.H
// Clase drivada de empleado
#ifndef JEFE_H_
#define JEFE_H_
#include "empleado.h"
#endif /*JEFE_H_*/
// JEFE.CPP
#include <iostream>
#include "jefe.h"
using namespace std;
Boss::Boss(const char *first, const char *last, float s)
: Employee(first, last)
{ weeklySalary = s > 0 ? s : 0; }
void Boss::setWeeklySalary(float s)
{ weeklySalary = s > 0 ? s : 0; }
// COMIS.H
// Trabajador por comisión derivado de Empleado
#ifndef COMIS_H_
#define COMIS_H_
#include "empleado.h"
#endif /*COMIS_H_*/
// COMIS.CPP
#include <iostream>
#include "comis.h"
using namespace std;
void CommissionWorker::setSalary(float s)
{ salary = s > 0 ? s : 0; }
void CommissionWorker::setCommission(float c)
{ commission = c > 0 ? c : 0; }
void CommissionWorker::setQuantity(int q)
{ quantity = q > 0 ? q : 0; }
// PIEZA.H
// Trabajador por pieza derivado de Empleado
#ifndef PIEZA_H_
#define PIEZA_H_
#include "empleado.h"
#endif /*PIEZA_H_*/
// PIEZA.CPP
#include <iostream>
#include "pieza.h"
using namespace std;
void PieceWorker::setWage(float w)
{ wagePerPiece = w > 0 ? w : 0; }
void PieceWorker::setQuantity(int q)
{ quantity = q > 0 ? q : 0; }
// HORA.H
// Trabajador por hora derivado de Empleado
#ifndef HORA_H_
#define HORA_H_
#include "empleado.h"
#endif /*HORA_H_*/
// HORA.CPP
#include <iostream>
#include "hora.h"
using namespace std;
void HourlyWorker::setHours(float h)
{ hours = h >= 0 && h < 168 ? h : 0; }
// main.cpp
#include <iostream>
#include <iomanip>
#include "empleado.h"
#include "jefe.h"
#include "comis.h"
#include "pieza.h"
#include "hora.h"
using namespace std;
int main(){
// formato de salida
cout << setiosflags(ios::showpoint) << setprecision(2);
ptr = &h;
ptr->print();
cout << " ganado $" << ptr->earnings();
h.print();
cout << " ganado $" << h.earnings();
class Shape {
public:
virtual float area() const { return 0.0; }
virtual float volume() const { return 0.0; }
virtual void printShapeName() const = 0; // virtual pura
};
#endif
// Punto.H
#ifndef PUNTO_H_
#define PUNTO_H_
#include <iostream>
#include "figura.h"
// Punto.CPP
#include <iostream.h>
#include "punto.h"
Point::Point(float a, float b)
{
x = a;
y = b;
}
// Circulo.H
#ifndef CIRCULO_H_
#define CIRCULO_H_
#include "punto.h"
void setRadius(float);
float getRadius() const;
virtual float area() const;
virtual void printShapeName() const { cout << "Circulo: ";
}
private:
float radius;
};
#endif /*CIRCULO_H_*/
// Circulo.CPP
#include <iostream>
#include <iomanip.h>
#include "circulo.h"
return output;
}
// Cilindro.H
#ifndef CILINDRO_H_
#define CILINDRO_H_
#include "circulo.h"
void setHeight(float);
virtual float area() const;
virtual float volume() const;
virtual void printShapeName() const { cout << "Cilindro: ";
}
private:
// Cilindro.CPP
#include <iostream>
#include <iomanip.h>
#include "cilindro.h"
void Cylinder::setHeight(float h)
{ height = h > 0 ? h : 0; }
// main.CPP
#include <iostream>
#include <iomanip.h>
using namespace std;
#include "figura.h"
#include "punto.h"
#include "circulo.h"
#include "cilindro.h"
int main(){
Point point(7, 11);
Circle circle(3.5, 22, 8);
Cylinder cylinder(10, 3.3, 10, 10);
circle.printShapeName();
cout << circle << endl;
cylinder.printShapeName();
cout << cylinder << "\n\n";
cout << setiosflags(ios::showpoint) << setprecision(2);
Shape *ptr; // apuntador de clase base
ptr = &circle;
ptr->printShapeName();
cout << "x = " << circle.getX() << "; y =" << circle.getY()
<< "\nArea = " << ptr->area()
<< "\nVolumen = " << ptr->volume() << "\n\n";
ptr = &cylinder;
ptr->printShapeName(); // dynamic binding
cout << "x = " << cylinder.getX() << "; y = " <<
cylinder.getY()
<< "\nArea = " << ptr->area()
<< "\nVolumen = " << ptr->volume() << endl;
return 0;
}
Ejemplo:
//ejemplo Prueba
class base {
public void quien(){
System.out.println("base");
}
}
}
}
pBase=objBase;
pBase.quien();
pBase=obj1;
pBase.quien();
pBase=obj2;
pBase.quien();
pBase=obj3;
pBase.quien();
pBase=obj4;
pBase.quien();
}
}
Es importante señalar que – al igual que en C++- los métodos que sean
redefinidos en clases derivadas, deben tener además de la misma firma que
método base, el mismo tipo de retorno. Si se declara en una clase derivada un
método con otro tipo de dato como retorno, se generará un error en tiempo de
compilación.
41
En C++, una clase se hace abstracta al declarar al menos uno de los métodos virtuales como puro.
Carlos Alberto Fernández y Fernández
- 312 -
Programación Orientada a Objetos
con C++, Java y Ruby
// Constructor
public Employee( String first, String last ) {
firstName = new String ( first );
lastName = new String( last );
}
public Circle() {
super( 0, 0 );
setRadius( 0 );
}
setHeight( h );
}
// Codigo de prueba
Ejemplo:
//programa Polimorfismo
interface IDrawable {
void draw();
}
System.out.println("Dibujando figuras:");
for (int i = 0; i < shapes.length; i++)
shapes[i].draw();
Polimorfismo en Ruby
Ejemplo:
#ejemplo Prueba
class Base
def quien
puts "base"
end
end
end
#codigo de prueba
def prueba
objBase= Base.new
obj1= Primera.new
obj2= Segunda.new
obj3= Tercera.new
obj4= Cuarta.new
pBase=objBase
pBase.quien
pBase=obj1
pBase.quien
pBase=obj2
pBase.quien
pBase=obj3
pBase.quien
pBase=obj4
pBase.quien
end
prueba
¿Y la clase abstracta?
class MiClase
def self.abstract?
return self == MiClase
end
end
Ejemplos de polimorfismo:
class Employee
attr_reader :firstName, :lastName
@firstName
@lastName
def self.abstract?
return self == Employee
end
# Inicializador
def initialize (first, last)
@firstName = String.new( first )
@lastName = String.new( last )
end
def setWeeklySalary( s )
@weeklySalary = ( s > 0 ? s : 0 )
Carlos Alberto Fernández y Fernández
- 328 -
Programación Orientada a Objetos
con C++, Java y Ruby
end
def to_s
return "Jefe: " + @firstName + " " + @lastName
end
end
def setWage( w )
@wagePerPiece = ( w > 0 ? w : 0 )
end
def setQuantity( q )
@quantity = ( q > 0 ? q : 0 )
end
def earnings
return quantity * wagePerPiece
end
def to_s
return "Trabajador por pieza: " + @firstName + " " +
@lastName
end
end
def setWage( w )
@wage = ( w > 0 ? w : 0 )
end
def setHours( h )
@hours = ( h >= 0 && h < 168 ? h : 0 )
end
def earnings
return @wage * @hours
end
def to_s
return "Trabajador por hora: " + @firstName + " " +
@lastName
end
end
def setSalary( s )
@salary = ( s > 0 ? s : 0 )
end
def setCommission( c )
@commission = ( c > 0 ? c : 0 )
end
def setQuantity( q )
@quantity = ( q > 0 ? q : 0 )
end
def earnings
return @salary + @commission * @quantity
end
def to_s
return "Trabajador por Comision : " + @firstName + " "
+ @lastName
end
end
150)
p = PieceWorker.new( "Andres Manuel", "Lopez Obrador", 2.5,
200 )
h = HourlyWorker.new( "Ernesto", "Zedillo", 13.75, 40 )
puts Employee.abstract?
class Shape
def self.abstract?
return self == Shape
end
def area
return 0.0
end
def volume
return 0.0
end
def getName
end
end
@x
@y # coordenadas del punto
def setPoint(a, b)
@x, @y = a, b
end
def to_s
return "[" + @x.to_s + ", " + @y.to_s + "]"
end
def getName
return "Punto"
end
end
@radius
def initialize(r, a, b)
super( a, b )
setRadius( r )
end
def setRadius(r)
@radius = ( r >= 0 ? r : 0 )
end
def area
return 3.14159 * radius * radius
end
def to_s
return "Centro = " + super + "; Radio = " +
@radius.to_s
end
def getName
return "Circulo "
end
end
def initialize(h, r, a, b)
super(r, a, b)
setHeight(h)
end
def setHeight(h)
@height = ( h >= 0 ? h : 0 )
end
def area
return 2 * super + 2 * 3.14159 * @radius * @height
end
def volume
return areaCircle * @height
end
def to_s
return super + "; Altura = " + @height.to_s
end
def getName
return "Cilindro "
end
end
# Codigo de prueba
point = Point.new( 7, 11 )
circle = Circle.new( 3.5, 22, 8 )
cylinder = Cylinder.new( 10, 3.3, 10, 10 )
arrayOfShapes=[]
arrayOfShapes[0 ] = point
arrayOfShapes[1 ] = circle
arrayOfShapes[2 ] = cylinder
Ejemplo:
// stack.h
// Clase de plantilla Pila
#ifndef STACK_H_
#define STACK_H_
//#include <iostream>
#endif /*STACK_H_*/
int main() {
Stack< double > doubleStack( 5 );
double f = 1.1;
cout << "Insertando elementos en doubleStack \n";
while ( doubleStack.push( f ) ) {
cout << f << ' ';
f += 1.1;
}
while ( doubleStack.pop( f ) )
cout << f << ' ';
while ( intStack.push( i ) ) {
cout << i << ' ';
++i;
}
while ( intStack.pop( i ) )
cout << i << ' ';
• Una plantilla de clase se puede derivar de una clase que no sea plantilla.
• Una clase que no sea de plantilla se puede derivar de una plantilla de clase.
Las plantillas de clase son una herramienta muy poderosa en C++. Esto ha
llevado a desarrollar lo que se conoce como STL. STL es el acrónimo de
Standard Template Library, y es una libreria de C++ que proporciona un conjunto
de clases contenedoras, iteradores y de algoritmos genericos:
La STL está altamente parametrizada, por lo que casi cada componente en la STL
es una plantilla [22]. Podemos usar por ejemplo la plantilla vector<T> para
hacer uso de vectores sin necesidad de preocuparnos del manejo de memoria:
Los algoritmos proporcionados por la STL ayudan a manipular los datos de los
contenedores [22]. Por ejemplo, podemos invertir el orden de los elementos de un
vector, usando el algoritmo reverse():
reverse(v.begin(), v.end()); // v[0]==17, v[1]==10, v[2]==7
Ejemplo:
#ifndef STACK_HPP_
#define STACK_HPP_
#include <vector>
public:
void push(T const&);
void pop();
T top() const; // regresa elemento en el tope
bool empty() const { // regresa si la pila esta vacia
return elems.empty();
}
};
template<typename T>
void Stack<T>::pop ()
{
if (elems.empty()) {
std::cout<<"Stack<>::pop(): pila vacia";
return;
}
elems.pop_back(); // remueve el ultimo elemento
}
#include <iostream>
#include <string>
#include <cstdlib>
#include "stack.hpp"
int main()
{
Stack<int> intStack; // pila de enteros
Stack<std::string> stringStack; // pila de strings
// manipulapila de enteros
intStack.push(7);
std::cout << intStack.top() << std::endl;
Sintaxis:
Ejemplo:
class Pair<T, U> {
private final T first;
private final U second;
public Pair(T first, U second) { this.first=first;
this.second=second; }
public T getFirst() { return first; }
public U getSecond() { return second; }
}
Esto produce un warning pero no un error. Es legal pero Pair es tomado como un
tipo “crudo” (raw type)42, pero la conversión de ese tipo de dato al tipo
parametrizado es lo que genera el warning.
Sintaxis:
interface NombreInterfaz <Lista de parámetros de tipos> { … }
Ejemplo:
interface IPair<T, U>{
public T getFirst();
public U getSecond();
}
42
Un raw type es un tipo especial de dato creado para facilitar la transición de código antiguo al nuevo
código soportando Generics.
Ver: http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#110257
Carlos Alberto Fernández y Fernández
- 345 -
Programación Orientada a Objetos
con C++, Java y Ruby
System.out.println("Obtén primer
elemento:"+ipair.getFirst());
System.out.println("Obtén segundo
elemento:"+ipair.getSecond());
}
Un requerimiento para el uso tipos genéricos en Java es que no pueden usarse tipo
de datos primitivos, porque los tipos primitivos o básicos no son subclases de
Object [24]. Por lo que sería ilegal por ejemplo querer instanciar Pair<int,
String> . La ventaja es que el uso de la clase Object significa que solo un
archivo de clase (.class) necesita ser generado por cada clase genérica [25].
Al igual que C++ con la STL, Java tiene un conjunto de clases genéricas
predefinidas. Su uso, al igual con las clases genéricas definidas por el
programador, no esta permitido para tpos primitivos, por lo que solo objetos
podrán ser contenidos. Las principales clases genéricas en Java son, como en la
STL, clases contenedoras o collecciones43. El Java Collections Framework (JCF)
es un conjunto de interfaces y clases definidos en los paquetes java.util y
java.util.concurrent.
43
Las colecciones en Java eran implementadas antes de la versión 1.5 pero sin el uso de clases genéricas. El
uso de versiones anteriores de colecciones con colecciones genéricas es permitido por compatibilidad hacia
atrás pero debe tenerse especial cuidado pues hay situaciones que el compilador no puede validar.
Carlos Alberto Fernández y Fernández
- 347 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
Manejo de Excepciones
try
{
// instrucciones donde las excepciones
// pueden ser generadas
}
• throw: Esta instrucción seguida por una expresión de un cierto tipo, genera
una excepción del tipo de la expresión. Esta instrucción debería ser
ejecutada dentro de algún bloque try, de manera directa o indirecta:
throw "Se genera una excepción de tipo char *";
Ejemplo:
// exceptions
#include <iostream>
using namespace std;
int main () {
try
{
throw 20;
}
catch (int e)
{
cout << "Una excepción ocurrió. Número: " << e << endl;
}
return 0;
}
Ejemplo:
// excepciones estándar
#include <iostream>
#include <exception>
using namespace std;
int main () {
try
{
throw myex;
}
catch (exception& e)
{
cout << e.what() << endl;
}
return 0;
}
Ejemplo:
// excepción bad_alloc
#include <iostream>
#include <exception>
using namespace std;
int main () {
try
{
int* myarray= new int[1000];
}
catch (exception& e)
{
cout << "Excepción estándar: " << e.what() << endl;
}
return 0;
}
¿Cómo funciona?
Sintaxis:
Ejemplo:
public class LanzaExcepcion {
public static void main(String argumentos[]) throws
ArithmeticException {
Los dos ejemplos vistos anteriormente, son capaces de lanzar una excepción
en un momento dado, pero hasta aquí no difieren en mucho en su ejecución, ya
que el resultado finalmente es la terminación del programa. En la siguiente
sección se menciona como podemos darles un manejo especial a las excepciones,
de tal forma que el resultado puede ser previsto por el programador.
Manejo de excepciones
• El bloque try.
• El bloque catch.
• El bloque finally.
El bloque try
Lo primero que hay que hacer para que un método sea capaz de tratar una
excepción generada por la máquina virtual Java o por el propio programa
mediante una instrucción throw, es encerrar las instrucciones susceptibles de
generarla en un bloque try.
try {
<instrucciones>
}
…
Cualquier excepción que se produzca dentro del bloque try será analizada
por el bloque o bloques catch que se verá en el punto siguiente. En el momento en
que se produzca la excepción, se abandona el bloque try y, por lo tanto, las
instrucciones que sigan al punto donde se produjo la excepción no serán
ejecutadas.
El bloque catch
Cada bloque try debe tener asociado por lo menos un bloque catch.
try {
<instrucciones>
} catch (TipoExcepción1 nombreVariable1) {
<instruccionesBloqueCatch1>
} catch (TipoExcepción2 nombreVariable2) {
<instruccionesBloqueCatch2>
}
...
catch (TipoExcepciónN nombreVariableN) {
<instruccionesBloqueCatchN>
}
Por cada bloque try pueden declararse uno o varios bloques catch, cada uno
de ellos capaz de tratar un tipo de excepción.
Carlos Alberto Fernández y Fernández
- 357 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
public class ExcepcionTratada {
public static void main(String argumentos[]) {
int i=5, j=0;
try {
int k=i/j;
System.out.println("Esto no se va a ejecutar.");
}
catch (ArithmeticException ex) {
System.out.println("Ha intentado dividir por
cero");
}
System.out.println("Fin del programa");
}
}
Por ejemplo:
El bloque finally
if (num2 == 0)
throw new DivisionByZeroException("/ entre 0");
Jerarquía de excepciones
44
Para un listado actual ver la documentación del jdk de Java más reciente.
Lista de Excepciones 45
o java.lang.Object
o java.lang.Throwable (implements java.io.Serializable)
o java.lang.Error
o java.lang.AssertionError
o java.lang.LinkageError
o java.lang.ClassCircularityError
o java.lang.ClassFormatError
o java.lang.UnsupportedClassVersionError
o java.lang.ExceptionInInitializerError
o java.lang.IncompatibleClassChangeError
o java.lang.AbstractMethodError
o java.lang.IllegalAccessError
o java.lang.InstantiationError
o java.lang.NoSuchFieldError
o java.lang.NoSuchMethodError
o java.lang.NoClassDefFoundError
o java.lang.UnsatisfiedLinkError
o java.lang.VerifyError
o java.lang.ThreadDeath
45
Lista obtenida de la documentación del jdk en su versión 1.6
Carlos Alberto Fernández y Fernández
- 363 -
Programación Orientada a Objetos
con C++, Java y Ruby
o java.lang.VirtualMachineError
o java.lang.InternalError
o java.lang.OutOfMemoryError
o java.lang.StackOverflowError
o java.lang.UnknownError
o java.lang.Object
o java.lang.Throwable (implements java.io.Serializable)
o java.lang.Exception
o java.lang.ClassNotFoundException
o java.lang.CloneNotSupportedException
o java.lang.IllegalAccessException
o java.lang.InstantiationException
o java.lang.InterruptedException
o java.lang.NoSuchFieldException
o java.lang.NoSuchMethodException
o java.lang.RuntimeException
o java.lang.ArithmeticException
o java.lang.ArrayStoreException
o java.lang.ClassCastException
o java.lang.EnumConstantNotPresentException
o java.lang.IllegalArgumentException
o java.lang.IllegalThreadStateException
o java.lang.NumberFormatException
o java.lang.IllegalMonitorStateException
o java.lang.IllegalStateException
o java.lang.IndexOutOfBoundsException
o java.lang.ArrayIndexOutOfBoundsException
o java.lang.StringIndexOutOfBoundsException
o java.lang.NegativeArraySizeException
o java.lang.NullPointerException
o java.lang.SecurityException
o java.lang.TypeNotPresentException
o java.lang.UnsupportedOperationException
o class java.lang.Object
o class java.lang.Throwable
o class java.lang.Error
o java.awt.AWTError
o class java.lang.Exception
o java.io.IOException
o java.io.EOFException
o java.io.FileNotFoundException
o java.io.InterruptedIOException
o java.io.UTFDataFormatException
o java.net.MalformedURLException
o java.net.ProtocolException
o java.net.SocketException
o java.net.UnknownHostException
Carlos Alberto Fernández y Fernández
- 365 -
Programación Orientada a Objetos
con C++, Java y Ruby
o java.net.UnknownServiceException
o RuntimeException
o java.util.EmptyStackException
o java.util.NoSuchElementException
o java.awt.AWTException
Afirmaciones en Java
Las afirmaciones por lo tanto son usadas para comprobar código que se
asume será verdadero, siendo la afirmación la parte responsable de verificar que
realmente es verdadero. Cada afirmación debe contener una expresión boleana
(boolean o Boolean).
Sintaxis:
assert Expression1;
ó:
assert Expression1 : Expression2 ;
Usando afirmaciones
i++;
assert i < max;
Errores detectados con afirmaciones deben ser errores que no deben pasar.
Es por esto que se lanza un subtipo de Error en lugar de un subtipo de Exception.
Si falla la validación de una afirmación se asume un error grave que nunca debe
pasar.
-enableassertions | -ea
-disableassertions | -da
Ejemplo:
//Recuerda habilitar el uso de afirmaciones
import java.io.IOException;
}
}
Ejemplos:
begin
expr..
[rescue [tipo_de_error [=> var],..]
expr..]..
[else
expr..]
[ensure
expr..]
end
La sintaxis anterior implica que podemos poner una serie de clausulas rescue
especificando diferentes tipos de errores que pueden ser “rescatados” y la clausula
else recibiría aquellos errores que no entren dentro de los especificados por
rescue.
La clansula ensure es usada para especificar código que queremos que se ejecute
independientemente del error generado. Por ejemplo:
begin
# Error...
rescue
# intento de recuperación...
retry # tratar de nuevo
ensure
# Este código es siempre ejecutado
end
Ejemplos:
def raise_exception
puts 'Antes de raise.'
raise 'Ocurrio un error'
puts 'Después de raise'
end
raise_exception
def raise_y_rescue
begin
puts 'Antes de raise.'
raise 'Ocurrio un error.'
puts 'Después de raise.'
rescue
puts 'Siendo rescatado.'
end
puts 'Despues del bloque begin - end.'
end
raise_y_rescue
begin
# ...
rescue UnaExepcion
# ...
rescue OtroTipoDeExepcion
# ...
else
# Otras exceciones
end
begin
raise "Probando excepciones."
rescue Exception => e
puts "Salida:"
puts e.message
puts e.backtrace.inspect
puts "fin salida."
end
Jerarquía de Excepciones
* Exception
o NoMemoryError
o ScriptError
+ LoadError
+ NotImplementedError
+ SyntaxError
o SignalException
+ Interrupt
o StandardError (default for rescue)
+ ArgumentError
+ IOError
# EOFError
+ IndexError
+ LocalJumpError
+ NameError
# NoMethodError
+ RangeError
# FloatDomainError
+ RegexpError
+ RuntimeError (default for raise)
+ SecurityError
+ SystemCallError
# Errno::*
+ SystemStackError
+ ThreadError
+ TypeError
+ ZeroDivisionError
o SystemExit
o fatal
Es posible en Ruby usar también los clásicos catch & throw los cuales son usados
comúnmente cuando es necesario saltar de un punto de anidamiento más
profundo [12].
Sintaxis:
catch (:label) do
#...
end
Ejemplo:
def pregunta pr
print pr
res = readline.chomp
throw :salida_solicitada if res == "!"
res
end
catch :salida_solicitada do
nombre = pregunta "Nombre: "
edad = pregunta "Edad: "
sexo = pregunta "Sexo: "
# ...
end
Ejemplo:
class MiHilo extends Thread {
Este pequeño ejemplo ejecuta dos hilos. Uno llamado mascar y otro silbar.
Por lo que el programa es capaz de "mascar" y "silbar" al mismo tiempo, aunque
como ya sabemos, en una computadora de un solo procesador tendrá que dejar de
mascar para poder silbar, y viceversa.
Estados de un hilo
entrando a
no-ejecutable
finalizando
Muerto
Cuando un hilo está ejecutándose pueden pasar varias cosas con ese hilo en
particular. El método start() llama en forma automática al método run(). Este
método contiene el código principal del hilo, algo así como un método main para
un programa principal.
Existen los métodos stop(), suspend() y resume(), pero estos han sido
desaprobados en la versión 2 de Java debido a que se consideran potencialmente
peligrosos para la ejecución de los programas concurrentes.46
nacido
start
listo
despachar
expiración (asignar un
de cuanto procesador)
notify
Finalizada e/s
notifyAll en ejecución
wait
sleep Emitir
solicitud de e/s
Fin de
ejecución
46
El que sean desaprobados no quiere decir que ya no puedan ser usados. Se conservan por compatibilidad
hacia atrás con el lenguaje, pero se ha visto que no es recomendable su uso. En algunos ejemplos pueden
aparecer estas instrucciones por simplicidad.
Carlos Alberto Fernández y Fernández
- 378 -
Programación Orientada a Objetos
con C++, Java y Ruby
La clase Thread
47
Para las características completas ver la documentación: Java Platform API Specification
Bajo este último esquema, es importante que un hilo delegue el control cada
determinado tiempo a hilos de igual prioridad. Para esto sirve poner a dormir el
hilo con sleep(), o ceder el control con el método yield(). Un método que tiene
estas consideraciones se conoce como hilo compartido, el caso contrario se
conoce como hilo egoísta.
Veamos una clase que implementa un hilo y cede el control a otros hilos.
48
Sin embargo debería siempre considerarse el uso de yield() si se piensa en sistemas multiplataformas.
Carlos Alberto Fernández y Fernández
- 380 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
class HiloEterno extends Thread {
import java.awt.*;
Dentro del AWT existen un gran número de clases con capacidades gráficas,
componentes y elementos para el manejo de eventos. La información completa de
cada clase se puede consultar en la documentación del jdk de Java.
Clases de ventana
49
Existe también conjunto de clases llamadas Swing, que se prevé que sustituyan al AWT ya que permiten
manipular y respetar el look and feel de cada ambiente gráfico.
Carlos Alberto Fernández y Fernández
- 383 -
Programación Orientada a Objetos
con C++, Java y Ruby
Clase Frame
Clase Dialog
Clase Filedialog
Ejemplo:
//clase HolaVentanas
import java.awt.*;
import java.awt.event.*;
public HolaVentanas() {
super("Hola Ventanas!"); //asigna titulo a la ventana
setSize(200,200); //define el tamaÒo de la ventana
addWindowListener(new
HolaVentanas.WindowEventHandler()); //asocia a los eventos de
la ventana
setVisible(true); //muestra la ventana en pantalla
Componentes gráficos
Veamos ahora una aplicación más grande y funcional, que incluya algunos
componentes gráficos básicos como los campos de texto (TextField), etiquetes
(Label) y botones (Button), los cuales son sólo algunos de los elementos gráficos
proporcionados por Java.
Carlos Alberto Fernández y Fernández
- 385 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
//Clase CalAhorro
import java.awt.*;
if (evt.target == boton)
{ // Obtener los datos del usuario
interes =
Double.valueOf(campo_interes.getText()).doubleValue();
cant_mensual = Double.valueOf(
campo_pago.getText()).doubleValue();
anios=Integer.valueOf(campo_anios.getText()).intValue();
cant_total.setText(String.valueOf(ahorro_total));
return true; // evento procesado
}
return false; // evento no procesado
}
setLayout(new GridLayout(5,2,3,2));
Ejemplo:
//clase Apuntador
import java.awt.*;
50
El método handleEvent pertenece al sistema antiguo de manejo de eventos, pero aún es soportado.
Carlos Alberto Fernández y Fernández
- 388 -
Programación Orientada a Objetos
con C++, Java y Ruby
"SW_RESIZE", "SE_RESIZE","NW_RESIZE","NW_RESIZE",
"NE_RESIZE", "N_RESIZE","S_RESIZE","W_RESIZE","E_RESIZE",
"HAND", "MOVE"};
return super.handleEvent(evt);
}
}
Es común que una aplicación gráfica necesite de menús como una forma de
ofrecer distintas posibilidades de operación del programa de acuerdo a la solicitud
del usuario. Para esto se incluyen clases que permiten el manejo de menús.
Clase MenuBar
Clase Menu
Una vez que se tiene la barra de menú, es necesario crear objetos de la clase
Menu, uno por cada opción de menú deseada. Posteriormente estos objetos se
asocian a la barra de menú:
Clase MenuItem
menu_archivo.add(new MenuItem("Abrir"));
menu_archivo.add(new MenuItem("Guardar"));
menu_editar.add(new MenuItem("Cortar"));
menu_archivo.add("Abrir");
menu_archivo.add("Guardar");
menu_editar.add("Cortar");
Ejemplo:
// clase PruebaMenu
import java.awt.*;
}
return false;
}
}
Manejo de Eventos
Introducción
java.util.EventObject
<<interfaz>>
java.util.EventListener
Evento
51
También llamada difusión simple.
52
Difusión múltiple.
Carlos Alberto Fernández y Fernández
- 396 -
Programación Orientada a Objetos
con C++, Java y Ruby
Ejemplo:
//programa EjemploEvento1
import java.awt.*;
import java.awt.event.*;
public EjemploEvento1() {
Button miBoton= new Button("boton");
add(miBoton);
}
f.pack();
f.setVisible(true); //puede ser usado en lugar de show()
}
}
Ejemplo:
//programa EjemploEvento2
import java.awt.*;
import java.awt.event.*;
public EjemploEvento2() {
Button miBoton= new Button("boton");
miBoton.addActionListener(
// se crea una clase anonima que implementa
ActionListener
new ActionListener () {
add(miBoton);
}
f.pack();
f.setVisible(true);
}
}
Esta clase también generará un archivo class, pero se le asignará después del
nombre de la clase un número que la identifique.
Adaptadores
Ejemplo:
//programa EjemploEvento3
import java.awt.*;
import java.awt.event.*;
public EjemploEvento3(){
// se le asigna un adaptador
miBotonSalir.addActionListener(new
MiAdaptador(MiAdaptador.SALIR, unDelegado));
}
}
}
public void maximizar(Frame f){
f.setSize(f.getToolkit().getScreenSize());
}
}
}
public void actionPerformed(ActionEvent e){
switch (tipoAccion){
case SALIR:
// se llama el metodo salirApl del delegado
elDelegado.salirApl();
break;
case MAXIMIZA:
// se llama al metodo maximizar pasando el
Frame que contiene el componente sobre el que se ha producido
el evento.
elDelegado.maximizar((Frame)
ventanaPrincipal);
break;
}
}
}
Ejemplo:
//Programa EjemploEvento4.java
import java.awt.*;
import java.awt.event.*;
// se instancia la aplicacion
EjemploEvento4 miApl = new EjemploEvento4();
}
}
// se le asigna un adaptador
miBotonSalir.addActionListener(new
MiAdaptador(MiAdaptador.SALIR, unaApl) );
switch (tipoAccion) {
case SALIR:
• Java SE. Java Platform Standard Edition, es la versión más común y popular
de Java. Contiene los servicios estándar para applets y aplicaciones, entrada
salida, prestaciones para desarrollo de la interfaz gráfica con el usuario, etc. La
mayor parte de lo visto sobre Java se encuentra en esta edición.
• Java EE. Java Platform Enterprise Edition, está basada en la versión estándar,
pero añade un conjunto de API's que permiten el desarrollo de clases de tipo
enterprise, dando mayor soporte a las aplicaciones servidor. Esta edición de
Java fue liberada apenas en diciembre de 1999, aunque algunas de las
tecnologías ya se encontraban disponibles desde antes.
Se hace una breve mención de las tecnologías con que cuenta Java EE, de
forma que puedan ser tomadas en cuenta en la construcción de aplicaciones Java.
• Servlets. Los servlets son la contraparte de los applets, mientras que estos
últimos corren en el cliente, los servlets son pequeñas aplicaciones que se
ejecutan del lado del servidor. Esto permite extender la funcionalidad de los
servidores de web ofreciendo programas basados en componentes e
independientes de la plataforma.
• JSP. Java Server Pages, es la respuesta de Java a las páginas ASP. Los JSP
son scripts compilados dentro de servlets53, pero con la diferencia de que los
JSP scripts no tienen código Java puro.
53
De hecho, JSP es una extensión de Java Servlets API.
Carlos Alberto Fernández y Fernández
- 409 -
Programación Orientada a Objetos
con C++, Java y Ruby
Tecnología Google
• APIs Diversas de Google. Google distribuye una serie de APIs para poder
desarroolar aplicaciones que utilicen sus recursos. Dentro de éstas se
pueden mencionar: para AJAX, para desarrollo de Gadgets, para manejo
de datos de Google, para YouTube, OpenSocial, manejo de Mapas
Y más lenguajes
Referencias
26. Naftalin, M. and Wadler, P. Java generics and collections. O'Reilly, Beijing
; Sebastopol, CA, 2007.
27. Díaz-Alejo Gómez, J.A., Programación con Java, IES Camp, Valencia,
España, Last access: September 2006
28. Arnold, K., Gosling, J. and Holmes, D. Java (TM) Programming Language,
The. Addison-Wesley Professional, 2005.
29. Sun Microsystems, Programming With Assertions, Sun Microsystems, 2002,
http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html, Last access: June
2007
30. Davis, R., Ruby QuickRef, 2004,
http://www.zenspider.com/Languages/Ruby/QuickRef.html, Last access:
June 2008