Mas Sobre Constructores
En el post anterior hablamos sobre el método especial "_new", que nos ayuda a dar valores a los parámetros o realizar instrucciones justo cuando instanciamos un objeto.Los métodos también admiten (al igual que las funciones y las subrutinas), parámetros opcionales (optional). Además tenemos funciones en gambas que permiten conocer que tipo de parámetro es el que se le esta pasando al instanciar la clase.
Con esta dos herramientas, podemos programar que un mismo método _new, pueda crear objetos usando diversos tipos y números de parámetros.
Por ejemplo:
Tenemos la clase ClassCirculo, con la cual se crean Circulos.
Podemos definir los circulos de diversas maneras:
- Forma 1: x, y, radio, nos dan la X e Y y radio (integer)
- Forma 2: x, y, radio, nos dan la X e Y y radio (pero son Float)
- Forma 3: classe Coordenada, radio (circulo dado el centro por la clase coordenada y su radio)
- Forma 4: clase coordenda1,coordenado2,coordenada3 (circulo que pase por 3 puntos)
Lo que tenemos que hacer es usar varias ordenes If... then,,, para que segun sea el tipo de parametro pasar crearlo.
Para saber el tipo de parámetro, usamos:
- La orden TypeOf(parametro1), nos devuelve un número que se identifica con el tipo de variable (ver http://www.gambasdoc.org/help/lang/typeof?v3 )
- Si sabemos que es un objeto Object.Type(parametro1), que nos dá el nombre de la clase.
¿Como se defineria la clase ClassCirculo?
-->
Public
Sub
_new(Optional
parametro1 As
Variant,
Optional
parametro2 As
Variant,
Optional
parametro3 As
Variant)
'
Forma: x, y, radio : nos dan la X e Y y radio (integer)
If
TypeOf(parametro1) =
gb.Integer
And
TypeOf(parametro2) =
gb.Integer
And
TypeOf(parametro3) =
gb.integer
Then
Print
"Me
pasan 3 numeros integer, en la forma X, Y, Radio"
'realizo
copia de propiedades...
'...
hx =
parametro1
hy =
parametro2
hradio =
parametro3
estado =
"iniciado"
Return
Else
'
Forma: x, y, radio : nos dan la X e Y y radio (pero son Float)
If
TypeOf(parametro1) =
gb.float
And
TypeOf(parametro2) =
gb.float
And
TypeOf(parametro3) =
gb.float
Then
Print
"Me
pasan 3 numeros float, en la forma X, Y, Radio"
'crearia
el circulo
'...
hx =
parametro1
hy =
parametro2
hradio =
parametro3
Return
Else
'
forma: classe Coordenada, radio (circulo dado el centro por la clase
coordenada y su radio)
If
Object.Type(parametro1)
=
"ClassCoordenada"
And
TypeOf(parametro2) =
gb.float
Then
Print
"Me
pasan una clase ClassCoordenada, y el Radio (float)"
'crearia
el circulo con los datos pasado
'....
'
Return
Else
'
Forma: clase coordenda1,coordenado2,coordenada3 (circulo que pase por
3 puntos)
If
Object.Type(parametro1)
=
"ClassCoordenada"
And
Object.Type(parametro2)
=
"ClassCoordenada"
And
Object.Type(parametro3)
=
"ClassCoordenada"
Then
Print
"Me
pasan 3 clases ClassCoordenada"
'se
crearia el circulo teniendo en cuenta 3 coordenadas.
'....
'
Return
Endif
Endif
Endif
Endif
¿como usar la clase?
-->
Print
"================================================================"
Print
"=
Constructores ="
Print
"================================================================"
'
Forma: x, y, radio : nos dan la X e Y y radio (integer)
Print
"Constructor
caso:"
c1 =
New
ClassCirculo(2,
3,
4)
'
Forma: x, y, radio : nos dan la X e Y y radio ( Float)
Print
"Constructor
caso:"
c2 =
New
ClassCirculo(2.3,
24.2,
34.2)
'
forma: classe Coordenada, radio (circulo dado el centro por la clase
coordenada y su radio (float))
Print
"Constructor
caso:"
c3 =
New
ClassCirculo(coord1, 34.3)
'
Forma: clase coordenda1,coordenado2,coordenada3 (circulo que pase por
3 puntos)
Print
"Constructor
caso:"
c4 =
New
ClassCirculo(coord1, coord2, coord3)
Hacer una Copia de un Objeto:
Para copiar variables en Gambas, usamos el operador igual "=".Por ejemplo
-->
dim
Nombre as
string
dim
NombreCopia as
string
Nombre=”Julio”
NombreCopia=nombre
print
Nombre, NombreCopia
Sin embargo, con objetos no podemos hacer lo mismo, ya que el operador igual ("=") lo que hace es copiar la referencia del objeto (no hace copia). Cualquier cambio que haríamos en el objecto copiado modificaria al objeto original.
-->
Print
"Coordenadas
Mal copiadas por referencia!!!: "
Print
coord1.escribe()
Print
coord2.escribe()
coord2.y
=
234343455
Print
"Coordenadas:
"
Print
coord1.escribe()
Print
coord2.escribe()
Obtenemos en pantalla...
Coordenadas Mal copiadas por referencia!!!:Como ves, al alterar la clase copiada (coord2), se modifica tambien la clase origen (coord1)
X: 23 Y: 34
X: 23 Y: 34
Coordenadas:
X: 23 Y: 234343455
X: 23 Y: 234343455
Para copiar objetos, tenemos que hacerlo mediante lineas de código, que se encarguen de copiar y asignar las propieades (sus valores) del objeto Origen a las otras propiedades del objeto_copia. Por ejemplo, con este método dentro de la clase ClassCoordenada
-->
'Esta
es la opcion más correcta vease comentarios...
Public
Sub
copia(origen As
ClassCoordenada)
Me.x = origen.x
Me.y = origen.y
End
Me.x = origen.x
Me.y = origen.y
End
Para usarlo:
-->
coord1 =
New
ClassCoordenada
coord2 =
New
ClassCoordenada
coord1.x
=
23
coord1.y
=
34
coord2.copia(coord1)
Print
"Coordenadas:
Copia mediante metodo "
Print
coord1.escribe()
Print
coord2.escribe()
coord2.y
=
3433445
Print
"Coordenadas
Cambio: "
Print
coord1.escribe()
Print
coord2.escribe()
Y es resultado...
Coordenadas: Copia mediante metodoComo veis, ahora si, se copia bien, ya que al modificar la clase copiada, la de origen no se modifica.
X: 23 Y: 34
X: 23 Y: 34
Coordenadas Cambio:
X: 23 Y: 34
X: 23 Y: 3433445
Para terminar, tambien podemos usar el método contructor para que crear una copia de un objeto:
-->
Public
Sub
_new(Optional
parametro1 As
Variant,
Optional
parametro2 As
Variant,
Optional
parametro3 As
Variant)
Dim
clase As
String
If
TypeOf(parametro1) =
gb.Object
And
If
Object.Type(parametro1)
=
"ClassCirculo"
Then
hy =
parametro1.y
hx =
parametro1.x
hradio =
parametro1.radio
estado =
parametro1.leerEstado()
Return
Endif
…..
…..
Y usarlo asi:
-->
Print
"Proceso
de copia de circulo.."
copia
=
New
ClassCirculo(c1)
Para más información: http://www.gambas-es.org/viewtopic.php?f=1&t=100&highlight=objetos
Descarga del Código Fuente de ejmplo. tanto de Sobre Constructores y Copia de Objetos : Enlace
Nota: Actualizacion 3/8/2013 (new)
Tras estudiar un ejemplo del foro de gambas de Francia (http://www.gambasforge.org/code-62-copier-un-controle-ou-un-conteneur-et-ses-enfants.html), sobre como clonar controels, he realizado algunos cambios para que nos sirva para objetos complejos (con propiedades que sean arrays, clases, variant, ...)
Os dejo aqui la función que lo hace:
Public
Sub
CopyObject(hObjeto As
Object)
As
Object
Dim
hNewMe As
Object
=
Object.New(Object.Type(hObjeto))
'se genera
un objeto de la mismo tipo que nos pasan
Dim
s As
String
'variable
utilizada para almacenar el valor de hclass.symbols
Dim
hclass As
Class
=
Object.Class(hObjeto)
'contiene
el valor de la clase del objeto
Dim
hChild As
Object
Dim
nuevoObjeto As
Object
Dim
caso As
Integer
'tipo de
dato de la propiedad del objeto
Dim
contador, a As
Integer
'para
usarlo en bucle si son arrays
Dim
arrayPosible As
Object
'Inicio
de la copia de las propiedades....
For
Each
s In hclass.Symbols
If
s =
"Chlidren"
Then
Continue
If
Not
hclass[s].ReadOnly
Then
caso =
TypeOf(Object.GetProperty(hObjeto,
s))
Select
Case
caso
Case
gb.Object
'la
propiedad es un objeto, vuelvo a llamar a la funcion para que me
extraiga los valores y no las referencias
nuevoObjeto =
CopyObject(Object.GetProperty(hObjeto,
s))
Object.SetProperty(hNewMe,
s, nuevoObjeto)
Try
contador =
Object.GetProperty(hObjeto,
s).count
If
Error
Then
'no
es un array
Else
For
a =
0
To
contador -
1
nuevoObjeto.add(Object.GetProperty(hObjeto,
s)[a])
Next
Endif
Default
'la
propiedad no es un objeto, copio el valor
Object.SetProperty(hNewMe,
s, Object.GetProperty(hObjeto,
s))
End
Select
Endif
Next
'devuelvo
la copia del objeto
Return
hNewMe
End
Y un ejemplo:
http://jsbsan.blogspot.com.es/2013/08/poo-en-gambas3-copiar-objetos.html
Nota 2:
Esta función copia tanto las propiedades como los métodos que tenga el objeto.
No copia variables publicas definidas dentro del objeto (ni por supuesto las privadas)
Hola,
ResponderEliminarquisiera preguntarte algunas dudas del apartado "Para copiar objetos".
La primera es que en la función copia no has puesto ningún return. ¿El return no es necesario en este caso? ¿Las funciones no tienen que utilizar return obligatoriamente?
La segunda duda es que dentro de esta función copia haces referenca a ME. ¿Este ME es el objeto de la ClassCoordenada que devuelve la función?
La tercera es que no entiendo cuando llamas a la función mediante coord2.copia(coord1), ¿qué es lo que ocurre con el objeto devuelto por la función? ¿Cómo lo interpreta gambas?
Gracias y excúsame por la batería de preguntas, mi nivel aún es un poco bajo.
Pablo
1º Pregunta: ¿El return no es necesario en este caso?
ResponderEliminarEn este caso no, ya que no devuelve ningun valor, lo que hace es asignarse a las propiedades del objeto, unos valores externos ("origen")
El código seria "correcto" asi:
Public Sub copia(origen As ClassCoordenada)
Me.x = origen.x
Me.y = origen.y
End
El tema es que, tanto si usas sub como function, hace lo que me interesa y no muestra ningun error... Lo correcto es usar "sub"
2) ¿Las funciones no tienen que utilizar return obligatoriamente?
Si. si es para devolver algo... en este caso no devulve nada...
Gambas en este caso es ambigüo, puedes hacer estas cosas y no daria error (ni te lo muestra). Lo suyo es haber definido como subrutina (sub) y no como funcion (function).
3) "ME", hace referencia al objeto actual.
Fijate como se usa el método copia:
coord2.copia(coord1)
Los valores de las propiedades del objeto coord1, son copiadas al objeto coord2, en el codigo fuente se pone "Me" para hacer referencia al mismo objeto del que se esta usando el método "copia"
4) La tercera es que no entiendo cuando llamas a la función mediante coord2.copia(coord1), ¿qué es lo que ocurre con el objeto devuelto por la función? ¿Cómo lo interpreta gambas?
Como te comento mas arriba, la funcion no devuelve nada.
Lo que Gambas hace es los valores de coord1 (propiedades "x" e "y"), los asigna a las propiedades "x" e "y" del objeto coord2.
Nota:
Cuando se habla de objetos, normalmente no se habla de funciones ni de subrutinas, sino de métodos.
Los métodos pueden o no devolver valores, y son los encargados de trabajar con las variables internas del objeto.
Nota:
Otra cosa que vi es que un "sub" tambien puede devolver valores, si pones un return. Ya te digo gambas es ambiguo...
"Gracias y excúsame por la batería de preguntas, mi nivel aún es un poco bajo."
Gracias a ti por preguntar, si tienes alguna duda me lo comentas.
Hola,
ResponderEliminarmuchas gracias por todas tus aclaraciones, ahora lo he entendido todo mucho mejor. Me encontraba con el problema de copiar objetos, y este post me ha sido de mucha utilidad. Bueno, a lo mejor en un futuro gambas nos permite copiar "automáticamente" objetos, con la misma facilidad que cuando copiamos variables, pero de momento hay que hacerlo "a mano".
Gracias de nuevo.
Un saludo.
Pablo
Me alegra que te sea de utilidad.
ResponderEliminarNota:
Modifico el articulo, para incluir la solución "correcta" y asi quede todo más claro
He añadido una nueva nota "Actualizacion 3/8/2013" al final del articulo, donde presento la forma de copiar objetos complejos.
Eliminar