Curso Básico de Programación
en Visual Basic
Entrega Treinta y nueve: 12/Jul/2001
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el índice lo puedes hacer
En la entrega anterior te prometí que en esta ocasión íbamos a ver cómo crear nuestras propias colecciones, pero, no va a ser así... como puedes comprobar, algunas veces NO cumplo lo que digo... je, je, je, pero no te preocupes que en la siguiente si que lo vamos a ver... es que no es plan de que te acostumbres a tener todo lo que quieras...
Lo que vamos a hacer es añadir más funcionalidad a la clase normal, y de paso aprendes alguna que otra cosilla, o afianzas lo que ya has aprendido, que de seguro no te vendrá mal.
¿Que podemos añadirle?
Pues por ejemplo un método o función que permita hacer una copia del objeto en cuestión.
Con esto, pretendo que comprendas que lo que estamos tratando o manejando no es una "simple" variable, sino un objeto, que como podrás comprobar, si no en estos ejemplos, si en otro código que veas por ahí... ya que me imagino que no sólo te contentarás con lo que yo te muestro, sino que te leerás la documentación del Visual Basic e incluso habrás comprado algún que otro libro sobre el tema este de la programación; en cualquier caso, debes saber que un objeto, ya sea un módulo de clase ya sea un control, no se puede copiar así por las buenas.Para que lo entiendas mejor: (espero)
Supongamos que tenemos una variable, por ejemplo la variable de tipo string sNombre, que tiene como valor "el Guille".
Sigamos suponiendo que queremos hacer una copia de dicha variable, (realmente de su contenido), en otra variable, por ejemplo en sCopia.
Para realizar dicha copia, lo único que hay que hacer es: sCopia = sNombre y a partir de ese momento, el contenido de sCopia será el mismo que el de sNombre, (en este caso de suposiciones, será "el Guille").
Si después cambiamos el contenido de la variable sNombre no afectará al contenido de sCopia, ya que lo que se hizo fue copiar el contenido de sNombre, es decir se creó una nueva cadena y se guardó en la variable sCopia.
(Si yo fuera un experto en representaciones gráficas, te mostraría un dibujito con las variables y sus contenidos, pero como soy un desastre para esto de las "representaciones", sobre todo si son gráficas, pues te lo imaginas o simplemente sigues leyendo, que puede ser que hasta te enteres de lo que estoy hablando...)
Para probarlo, muestra el contenido de las dos variables, cambia el contenido de sNombre y vuelve a mostrar, verás que cada una de las variables tiene un valor distinto.¿Cómo? Que quieres ver el código completo... ¡Valeeee! ¡No insistas!, aquí lo tienes:
Crea un nuevo proyecto e inserta este código en el evento Form_LoadShow ' Por si se te olvida ponerlo... Dim sNombre As String Dim sCopia As String ' Asignamos el contenido a sNombre y hacemos la copia sNombre = "el Guille" sCopia = sNombre ' Mostramos los contenidos Print "El original: " & sNombre Print "La copia: " & sCopia ' Cambiamos el contenido de sNombre sNombre = "Guillermo" ' Volvemos a mostrar Print Print "El original: " & sNombre Print "La copia: " & sCopiaComo podrás comprobar, el original cambia, pero la copia permanece igual. Es decir, el que se cambie el original no afecta a la copia, ya que son dos "cosas" distintas.
Pero esto mismo no se puede hacer con los objetos. Al menos no de la forma simple de una asignación.
Para que sepas por dónde van los tiros, practiquemos con un ejemplo.Supongamos, (sigo suponiendo, pero en estos casos, deberías "meterte" de lleno en el tema y convertir estas suposiciones en código), que queremos hacer una copia de un objeto del tipo cColega, (la clase que hemos estado usando en las entregas anteriores y de la cual más tarde te mostraré el código completo, ya que en las entregas anteriores no lo hice, y sólo te mostré parte del código y he recibido algunas quejas indicándome que faltaba código... mea culpa!)
Pero para no caer en errores de suposiciones, (algunas veces supongo que entiendes lo que digo y puede que "suponga" mal, así que... dejémonos de suposiciones y vayamos a cosas concretas), te voy a mostrar el código completo para que entiendas lo que quiero explicarte... que con tanto suponer y tanta parrafada, no se si te habrás perdido o seguirás en sintonía...Declaramos una variable para que contenga un objeto del tipo cColega y le asignamos algún valor:
Dim tColega As cColega ' La variable que contendrá un objeto del tipo cColega
Set tColega = New cColega ' Ahora está preparada para contener datos
tColega.Nombre = "Guille" ' Asignamos los datos
tColega.email = "[email protected]"Ahora creamos otra variable en la que queremos copiar lo que tiene el objeto tColega:
Dim CopiaColega As cColega
Set CopiaColega = New cColega ' Creamos un nuevo objeto, aunque, como después verás, no es necesarioSi hacemos esta asignación: CopiaColega = tColega, recibiremos un error, ya que Visual Basic espera que se estén copiando datos normales, en este caso espera que tanto CopiaColega como tColega tengan propiedades por defecto que se puedan copiar de la misma forma que se copian dos variables normales (como vimos en el caso anterior de sNombre y sCopia)
Cuando queremos "copiar" objetos, hay que usar SET, (no comento más, ya que después lo aclaro), por tanto, lo que se debería hacer es:
Set CopiaColega = tColega
Pero vamos a comprobar que no es oro todo lo que reluce.
Mostramos el contenido de CopiaColega
Text1.Text = "Contenido de CopiaColega: " & vbCrLf & CopiaColega.Nombre & " " & CopiaColega.email
Ahora cambiamos el nombre de tColega
tColega.Nombre = "Guillermo"
Y volvemos a mostrar el contenido de CopiaColega
Text1.Text = Text1.Text & vbCrLf & _
"Contenido de CopiaColega después de cambiar el nombre de tColega: " & vbCrLf & _
CopiaColega.Nombre & " " & CopiaColega.email & vbCrLf
Para probar esto que te digo y puedas ver y no tener que creértelo porque yo te lo diga, en el formulario que tienes creado de la prueba anterior...
¿cómo? ¿que no has probado lo anterior? entonces, tendrás que crear un nuevo proyecto... (si quieres, claro)
Añade un CommandButton (Command1) y una caja de texto (Text1) con la propiedad MultiLine = True y ScrollBars = Both y pega el código, (sí, lo que está en negrita, incluso la asignación que da el error, para que compruebes que es verdad y que da un error, así vas aprendiendo de los errores...)
Pulsa F5 y haz click en el botón, verás que es lo que ocurre.
Si todo va como debería ir, te habrá mostrado esto:Contenido de CopiaColega:
Guille [email protected]
Contenido de CopiaColega después de cambiar el nombre de tColega:
Guillermo [email protected]
O sea que no teníamos una copia... entonces ¿que tenemos?
Pues, dos variables que "apuntan" al mismo objeto. Con las consecuencias que esto tiene: que si se modifica el contenido de una de las variables, el otro objeto también "aparenta" que se ha modificado... y digo aparenta, porque en realidad sólo existe un objeto del tipo cColega en la memoria, pero hay dos variables que apuntan a ese objeto.
En otros lenguajes de programación sería algo así como un puntero.Como puedes comprobar, me repito, (hace un par de entregas vimos algo de esto), pero es para que te quede bien claro el concepto.
Entonces... ¿cómo se puede hacer una copia de un objeto?
Pues manualmente, copiando cada una de las propiedades del objeto original en la copia.
Para este caso si que es necesario declarar el objeto de destino como NEW, ya que, en el caso anterior, no era necesario crear un nuevo objeto cuando lo que "pretendíamos" era "apuntar" al mismo objeto en memoria.
Pruébalo quitando la línea con este código: Set CopiaColega = New cColega y verás que funciona igual (de mal)
La explicación es: que al ser una variable que simplemente hace referencia a un objeto ya existente, no es necesario crear un nuevo objeto que después no se va a usar.Veamos el código de la segunda prueba, haciendo copia de cada una de las propiedades.
Añade un nuevo botón e inserta este código, después pruébalo y verás que el cambio del original no afecta a la copia, por la sencilla razón de que son dos objetos totalmente diferentes.Private Sub Command2_Click() ' Creamos una variable y le asignamos datos Dim tColega As cColega ' La variable que contendrá un objeto del tipo cColega Set tColega = New cColega ' Ahora está preparada para contener datos tColega.Nombre = "Guille" ' Asignamos los datos tColega.email = "[email protected]" ' ' Creamos otra variable en la que queremos copiar ' lo que tiene el objeto tColega: Dim CopiaColega As cColega Set CopiaColega = New cColega ' Ahora copiamos cada una de las propiedades: CopiaColega.Nombre = tColega.Nombre CopiaColega.email = tColega.email ' Mostramos el contenido de CopiaColega Text1.Text = "Contenido de CopiaColega: " & vbCrLf & CopiaColega.Nombre & " " & CopiaColega.email ' Ahora cambiamos el nombre de tColega tColega.Nombre = "Guillermo" ' Y volvemos a mostrar el contenido de CopiaColega Text1.Text = Text1.Text & vbCrLf & "Contenido de CopiaColega después de cambiar el nombre de tColega: " & vbCrLf & CopiaColega.Nombre & " " & CopiaColega.email & vbCrLf ' En este caso no se ha alterado el valor de CopiaColega... como era de esperar End SubPues esto mismo es lo que tendríamos que hacer en un método que hiciese una copia del objeto: copiar cada una de las propiedades de dicho objeto. Este tipo de métodos suele llamarse Clone, (por lo de clonación o copia idéntica), y se podría codificar de esta forma:
Public Function Clone() As cColega ' Esta función devolverá una copia "nueva" de éste mismo objeto (12/Jul/01) ' Dim nuevoColega As cColega ' Un objeto del tipo cColega ' Set nuevoColega = New cColega ' Crear un nuevo objeto ' ' Asignar cada una de las propiedades de esta clase With nuevoColega .email = Me.email .FechaNacimiento = Me.FechaNacimiento .Nombre = Me.Nombre End With ' Devolver el objeto "cloneado" Set Clone = nuevoColega End FunctionTe explico un poco todo esto:
- La función devuelve un objeto del mismo tipo que la clase, ya que de lo que se trata es de hacer una copia del objeto en sí.
- Se crea una variable temporal del tipo a devolver, (que es del mismo tipo que el objeto o clase), y se asigna un NUEVO objeto a dicha variable.
- Se asigna al nuevo objeto los valores del objeto que implementa el método Clone, para ello se usa ME, aunque sólo para mayor claridad, de ésta forma sabes que se está refiriendo al propio objeto en el que se ha creado la función.
- Por último se devuelve una referencia al nuevo objeto creado y con los datos copiados. El SET es necesario por lo que antes te he comentado de que lo que se quiere "copiar" es el objeto entero. En esta ocasión SET Clone = nuevoColega devuelve una referencia al objeto nuevoColega que no es ni más ni menos que el NUEVO objeto que acabamos de crear.
Para usarlo, simplemente asignaremos a la variable de destino lo que la función (o método) Clone devuelva:
Set CopiaColega = tColega.Clone
que no es ni más ni menos que una "nueva" copia del objeto tColega.
Como puedes comprobar en la función Clone lo único que hacemos es "encapsular" lo que antes hicimos manualmente, es decir "ocultamos" lo que la función hace para copiar el objeto, ya que al usuario lo único que le interesa es saber que ése método hace una nueva copia del objeto que lo implementa. Y si añadimos nuevas propiedades a la clase, lo único que tendríamos que hacer es añadir el código correspondiente para que las nuevas propiedades también se copien al utilizar el método Clone.Veamos el código necesario para "probar" que todo esto que digo funciona.
Añade un nuevo botón al formulario y pega el siguiente código:Private Sub Command3_Click() ' Creamos una variable y le asignamos datos Dim tColega As cColega ' La variable que contendrá un objeto del tipo cColega Set tColega = New cColega ' Ahora está preparada para contener datos tColega.Nombre = "Guille" ' Asignamos los datos tColega.email = "[email protected]" ' ' Creamos otra variable en la que queremos copiar ' lo que tiene el objeto tColega: Dim CopiaColega As cColega ' ' No es necesario crear el nuevo objeto, ya que el método Clone ' devuelve un nuevo objeto 'Set CopiaColega = New cColega ' ' Hacemos una clonación Set CopiaColega = tColega.Clone ' ' Mostramos el contenido de CopiaColega Text1.Text = "Contenido de CopiaColega: " & vbCrLf & CopiaColega.Nombre & " " & CopiaColega.email ' Ahora cambiamos el nombre de tColega tColega.Nombre = "Guillermo" ' Y volvemos a mostrar el contenido de CopiaColega Text1.Text = Text1.Text & vbCrLf & "Contenido de CopiaColega después de cambiar el nombre de tColega: " & vbCrLf & CopiaColega.Nombre & " " & CopiaColega.email & vbCrLf ' ' Usando Clone tampoco se altera el objeto copiado ' ' Cambiemos el contenido del nombre de la copia CopiaColega.Nombre = "Pepe" ' Mostramos el contenido de la propiedad Nombre de los dos objetos Text1.Text = Text1.Text & vbCrLf & "Contenido de tColega.Nombre: " & tColega.Nombre Text1.Text = Text1.Text & vbCrLf & "Contenido de CopiaColega.Nombre: " & CopiaColega.Nombre End SubEjecuta el programa y pulsa en el botón que acabas de añadir, verás que te muestra esto:
Contenido de CopiaColega:
Guille [email protected]
Contenido de CopiaColega después de cambiar el nombre de tColega:
Guille [email protected]
Contenido de tColega.Nombre: Guillermo
Contenido de CopiaColega.Nombre: Pepe
Es decir, que los cambios que se hagan a cualquiera de las dos variables serán independientes y no se "mezclarán", por la sencilla razón de que cada una de las variables "apunta" a un objeto diferente.
Otra forma de clonar objetos
Existe otra forma de hacer clonaciones de objetos. Pero para ello hay que tener el Visual Basic 6.0, ya que con las versiones anteriores no funciona.
Te dejo el link a la página que tiene el código de ejemplo, (y la página explicativa), para que sepas cómo hacerlo, por ahora no te doy más explicaciones que las que pueda haber en los comentarios y en dicha página, entre otras cosas porque se tratan temas que aún no se han explicado, así que... eso es lo que hay, pero al menos hay algo, que en definitiva es lo importante ¿verdad?Link a la página de clonación de objetos usando Visual Basic 6.0
Y hasta aquí hemos llegado.
En la próxima entrega, posiblemente, veremos cómo crear nuestras propias colecciones... espero que en esa ocasión sea así... si es que antes no se me ocurre alguna cosilla nueva... ¡ya veremos!Nos vemos
Guillermo
P.S.
Aquí tienes el código completo de la clase y el proyecto de prueba: basico39_cod.zip 3.93 KB