![]() |
![]() |
![]() |
![]() |
![]() |
FTP | ![]() |
![]() |
CCD | ![]() |
![]() |
Buscar | ![]() |
![]() |
Trucos | ![]() |
![]() |
Trabajo | ![]() |
![]() |
Foros | ![]() |
|
Registrarse | FAQ | Miembros | Calendario | Guía de estilo | Temas de Hoy |
![]() |
|
Herramientas | Buscar en Tema | Desplegado |
#1
|
||||
|
||||
Duplicar "objetos"
Hola.
A ver, os explico el tema, puede q la pregunta sea muy estupida (pero no habia usado hasta hace poco la POO en delphi xD). La cosa esq tengo un objeto propio, q no es nativo del delphi, como por ejemplo:
o
Y quiero duplicarlo, osea crear 2 objetos iguales pero q sean independientes. Lo q esta claro esq si hacemos algo parecido a esto:
Ok, esto es normal q pase, ya q lo unico q hace es q el obj2 copia el puntero de obj1, y q si liberamos el obj1, el obj2 por asociacion se libera tambien, pero mi pregunta viene aqui: ¿Como lo hago para crear un objeto duplicado identico pero independiente uno del otro? He buscado por el foro, "copiar objeto", y me ha salido un post parecido a este, pero era para copiar Componentes visuales, y una de las respuestas me dio una idea, y es el "Assign", pero claro mis clases no tienen este proceso. ¿Deberia implementarla o heredarla de un objeto de nivel mas alto? ¿Hay alguna solucion facil y q no sepa q existe (q seria lo mas seguro xD)? Ahi va el tema, gracias por adelantado. Saludos. |
#2
|
||||
|
||||
Hola,
Reconozco que saco la frase de contexto, pero, es que me intriga de veras: ¿a qué te refieres cuando dices... Cita:
![]() |
#3
|
||||
|
||||
A mi tb me costo escribirlo, a ver si puedo definirlo de otra forma, hehe
Me refiero a q se cree una segunda instancia, q sea una copia de la primera (vamos con los mismos valores) pero q si elimino la primera, esta segunda (la nueva) no se vea afectada de ninguna forma y siga funcionando tranquilamente. No se si me he explicado mejor (en mi cabeza lo tengo muy claro, pero me cuesta definirlo de una forma q se entienda bien xDD) El mismo ejemplo, pero mostrado de otra forma:
Saludos. Última edición por xEsk fecha: 12-08-2006 a las 16:33:59. |
#4
|
||||
|
||||
Hola,
Bueno. Ahora creo haberte entendido. Me parece que el concepto sería "clonar" un objeto. Al menos así lo entiendo yo desde que conozco (a medias) la interface "ICloneable" disponible en la clase "System" de la plataforma .NET. En esta página (Delphi Basics) se trata sobre dicha interfaz, y, creo que la misma consigue está ahí para echar una mano a lo que te propones. Empero,... la verdad es que yo me pierdo un poco hablando de estos temas. A mí se me ocurre que si el objeto que quieres "clonar" no es muy "complejo", el mismo podría contar con un método (especificado o no por alguna interfaz al uso, que no sé si existe en Delphi, o si merecería la pena, si se ganaría algo), que el objeto contara con un método, digo, que fuera el encargado de la tarea que nos ocupa. Yo imagino algo así, pero, intuyo que podría mejorarse mucho, que me meto en temas que no comprendo bien. Parece ser que en esto de clonar objetos puede tirarse por dos caminos: Cita:
Una prueba podría resultar más o menos esto:
|
#5
|
||||
|
||||
Hola.
Antes q nada, gracias por perder tu precioso tiempo conmigo. Si, tienes razon q seria mucho mas sencillo llamarlo clonar. Tu solucion es una de mis primeras pensadas, pero luego como tu bien resaltas, si no son objetos complejos, cosa q no es el caso, heheh (vaya mala pata xD), ya q la clase q quiero clonar tiene bastantes propiededes, q a su vez estas tambien son clases con sus propiedades. Por el momento, la solucion mas cutre q se me ocurre, es intentar eviatar la necesidad de clonar. Despues de escribir este mensaje voy a leer el link q me has pasado. Saludos. |
#6
|
||||
|
||||
Pues si es complejo... a lo facil.
Deriva de TComponent que ya tienes los métodos Assign. Eso sí, deberás mirar como manipulas memoria dentro de tu objeto, pero en principio sería algo asi:
Si indagas por la VCL y la ayuda de Assign, creo que te puede hacer la vida más fácil. Alguna vez, para guardar un objeto en disco con SaveToStream, simplemente cambié el TObject por TComponent y todo resuelto, aunque creo que para tí no será tan simple. Saludos
__________________
Si usted entendió mi comentario, contácteme y gustosamente, se lo volveré a explicar hasta que no lo entienda, Gracias. |
#7
|
||||
|
||||
Hola,
Cita:
Cita:
Cita:
Léase la ayuda del método "Assing" de "TPersistent", pero, vamos aquí a ver el código fuente de dicho método:
Es decir... (atreviéndome un poco y por lo que he entendido en la ayuda), se averigua primero si el objeto "origen" no es "nil", y, en caso de que no sea "nil" se llama al método "AssingTo" del propio objeto "origen". En caso contrario se produce un error. Continuemos con el método "AssingTo", que se encuentra también la clase "TPersistent" declarado como un método protegido y virtual. ("Assing" está declarado como virtual también, pero es un método público). Este es el código fuente del método "AssingTo" de la clase "TPersistent":
No sé qué les parecerá a ustedes, pero, me parece que se está queriendo decir: "no debes llamar a este método desde un objeto "TPersistent", sino desde algún objeto que implemente este método virtual, más aún, no debes llamar a "AssingTo", directamente, sino que llama al método "Assing", que ya se encargará de llamarme a mí.". ![]() Casi termino diciendo que no sabré dar una solución, como no sea por aproximación y según escribo esto, pero, si derivas un objeto de "TComponent", como si lo derivas de "TPersistent", no harás sino producir un error si llamas al método de dicho objeto "Assing", puesto ya hemos visto que "TPersistent" quiere (al declararlos como virtuales) que sean las clases derivadas de ella las que implementen los métodos "Assing" y "AssingTo". Como "TComponent" no implementa dichos métodos virtuales, aunque deriva de "TPersistent", resulta que algo como esto deriva en una excepción de tipo "EConvertedError":
¿Y entonces? ¿Cómo podemos clonar un objeto, duplicarlo o como lo queramos llamar? Pues a mí después de todo esto que he escrito para ver si me daba alguna idea, no me queda sino pensar en que los objetos a clonar deben implementar por su cuenta los métodos "Assing" y "AssingTo", y derivar de "TPersistent", directa o indirectamente. Así que, no sé yo de qué objetos estamos hablando, pero, la clonación de un objeto a mí no me parece nada sencilla. Claro que yo de esto entiendo más bien poco, pero, si lo que he dicho tiene algún sentido, los objetos, las propiedades que fueran a su vez objetos, tendrían que contar con métodos "Assing" y "AssingTo", como digo, y además estaría aquello de tener que decidir entre las dos opciones que parece que hay, como poco: Cita:
![]() |
#8
|
|||
|
|||
Confirmo que lo que ha dicho Dec es correcto, para una clase definida por
el programador, es el propio programador el que debe crear el metodo que clone el objeto, es imposible que esto se haga de forma automatica, porque dado un objeto mas o menos complejo, realmente podria haber varias formas distintas de clonarlo. Cualquier objeto suele tener definidas propiedades o variables que apuntan a a su vez otros objetos. Cuando se quiere clonar el objeto estas propiedades o variables, hay que mirarlas una por una y decidir si tambien hay que clonarlas o no. Habra propiedades que si tendremos que clonar y otras que no porque son comunes para todas las instancias, incluso puede haber otras propiedades que no estaria claro si hay que clonarlas. Por ejemplo si tenemos un objeto con una propiedad "parent" que hace referencia a un objeto "padre", esta claro que esta propiedad no se debe clonar y duplicar en el objeto nuevo, luego quizas el objeto clonado deberia mantener una referencia al mismo "parent", o quizas tambien tenemos otra opcion que es crear el objeto clonado sin padre, con valor nulo, asi que tendra que decidir el programador que es lo mas adecuado. Otro ejemplo, si dentro de un objeto tenemos una variable que hace referencia a un objeto TScreen, en un objeto clonado tendriamos que mantener exactamente el mismo objeto ya que solo puede existir un unico objeto TScreen en una aplicacon de delphi (este objeto hace referencia a la pantalla de Windows que normalmente solo hay una). Saludos |
#9
|
||||
|
||||
![]() ¡Hola a todos!
He leído con interés el tema sin poder evitar remontarme a marzo de 2000, cuando buscaba algo similar a lo planteado por xEsk. En aquel entonces, indagando en la unidad System.pas de Delphi 3 o 4 (no recuerdo la versión exacta), encontré un par de funciones que llamaron mucho mi atención: _CopyRecord y _CopyObject (si, la “famosa” _CopyObject, el mayor misterio de la unidad System). Bien, resulta que sí es posible hacer una clonación superficial (shallow) o profunda (deep) —con mucho más esfuerzo— de un objeto en Delphi Win32, sin importar su clase, sin tener que redefinir la implementación de métodos como Assign o AssignTo. Pero el precio es, digamos, bastante incómodo. Habiendo aprendido que las funciones de la bien llamada magia del compilador, cuyos nombres inician con un guión bajo (“_”), y que generalmente fueron escritas en lenguaje ensamblador, son las rutinas que el compilador encadena como resultado de ciertas sentencias de código fuente, me pregunté «¿dónde utiliza el compilador la función _CopyRecord?». Encontrar la respuesta no fue difícil. Cada vez que el compilador encuentra una sentencia como «Registro1 := Registro2;», siendo Registro1 y Registro2 dos variables de un mismo tipo record (llamado struct en otros lenguajes), el código máquina resultante es una llamada a la función _CopyRecord, la cual recibe como parámetros el registro destino, el registro origen y la información estructural del tipo de dato: Cita:
![]() Entonces, la siguiente pregunta que me hice fue «¿dónde utiliza el compilador la función _CopyObject?»...Llevo cinco años preguntándome lo mismo. La intriga resulta de analizar tres cosas: 1. En el código fuente de todas las unidades nativas de Delphi no hay una sola referencia a la función _CopyObject. 2. Aparentemente, no hay ninguna sentencia Object Pascal que se pueda considerar traducible como una llamada a esta función («Objeto1 := Objeto2;» no vale, es una simple copia de puntero; «Objeto1^ := Objeto2^;» tampoco, ya que el compilador no permite esa sintaxis con variables objeto). 3. Curiosamente, _CopyObject llama a la función _CopyRecord, pero sólo una vez. Lo cual significa que sólo clona los campos del objeto que hayan sido directamente declarados por una clase. Para clonarlo por completo, habría que llamar a _CopyRecord por cada una de las clases involucradas en la jerarquía del objeto a copiar. Menciono lo anterior en base a las pruebas que realicé en aquel entonces. Ante esto, veo tres posibles respuestas a la intriga: 1. Que la función _CopyObject es utilizada para asignaciones de variables objeto object (clases estilo Turbo Pascal), no class. 2. Que la función _CopyObject es utilizada desde afuera, por algún lenguaje compatible con Delphi, como C++ Builder. 3. Que la función _CopyObject sea una asignatura pendiente, algo dejado a medias en la unidad System.pas. Habría que hacer algunas pruebas e indagaciones adicionales para develar el misterio. ![]() Admito que no sé mucho de lenguaje ensamblador, por lo que expongo aquí una copia de la función _CopyObject de Delphi 7 (que me parece no ha variado desde entonces). Si alguno de los lectores es ducho en el tema y tiene la gentileza de explicarnos cómo entiende este código fuente, más de un programador “paranoico” le estaremos agradecidos. ![]()
(el código de _CopyRecord y otras funciones mágicas puede ser visto en el archivo System.pas de muchas versiones de Delphi). ¿Logré clonar objetos en aquella aventura? Si. ¿Cómo lo hice? Basándome en el código de la rara función _CopyObject, creando una nueva función que encapsulara y llamara iterativamente a la función _CopyRecord por cada clase existente en la jerarquía del objeto a clonar. Aquí el código de mi función:
Varias de las funciones de biblioteca referenciadas pueden ser sustituidas sin muchos problemas por llamadas a funciones nativas (pido disculpas por el robótico estilo que empleaba hasta hace pocos años ![]() Pero quien ya se haya puesto a trabajar en esto se topará con una interrogante final: «¿Cómo hago para llamar a la función _CopyRecord?». Ahí estuvo el principal obstáculo. _CopyRecord es una función interna de System.pas, no puede ser referenciada explícitamente en el código fuente de otra unidad. Lo primero que se me ocurrió fue crear una nueva unidad y poner ahí una copia de la función _CopyRecord, pero de inmediato descarté ese camino, ya que _CopyRecord llama directa e indirectamente a un buen número de otras funciones internas. Así que la solución más práctica que encontré fue clonar (hablando de) la unidad System.pas, creando mi propia "System2.pas” con una función _CopyRecord perfectamente declarada para poder ser utilizada desde afuera.
Para crear un objeto clon, un ejemplo podría ser:
De esta forma sí es viable clonar objetos en Delphi no .NET, y, como se puede ver, el precio resulta incómodo. Desaconsejo esta chapucera práctica de robarle el código privado a System.pas porque uno nunca sabe cuándo Borland decidirá hacer un cambio que teóricamente no debería afectar al programador. Además, se presentan muchos problemas cuando se trata de clonar objetos que tienen reglas de negocio relacionadas con la asignación de valores a sus propiedades (la clonación las pasa por alto), cuando los objetos guardan referencias a otros objetos, y, peor aún, cuando esas referencias son simples identificadores (handles) a objetos de alguna API (como es el caso de la mayoría de los componentes visuales). La clonación puede resultar desde inestable hasta caótica. ![]() Quizá por eso Borland decidió suspender o reservarse la función _CopyObject. O quizá pensaron «Debemos estudiar mejor este asunto, tal vez en el futuro nos pongamos de acuerdo los fabricantes para establecer un estándar de clonación controlada. No le pongamos clonación a Delphi todavía, esperemos mejores tiempos, veamos primero cómo les resulta a otros...». Java se aventuró a incluir esta característica y al parecer Microsoft, tarde, aunque nada perezoso, reinventó el hilo negro llamándolo interfaz ICloneable de .NET. Sólo me resta decir que sugiero manejar con reserva primitivos métodos de clonación como el que expuse. Personalmente, la experiencia vivida me resultó más un ejercicio de aprendizaje que una solución a problemas importantes. Tal vez xEsk debería hablarnos de cuál es el objetivo concreto que persigue para proponerle mejores alternativas. Ah, y aún tengo la esperanza de que alguien me explique la función _CopyObject. ![]() Un abrazo clonado. Al González. ![]() Última edición por Al González fecha: 14-08-2006 a las 00:59:13. |
#10
|
||||
|
||||
Al González, muy interesante tu respuesta... sin duda.
Por el momento lo he solucionado, evitando la clonacion, y me funciona bien. El motivo por el cual queria clonar objetos, es pq este objeto (junto con algunas de sus propiedades) necesitan de internet para rellenar sus propiedades, y bajarase 4 (o mas) veces la misma informacion para cambiar solo un par de propiedades, me parecia exagerado, asi q pense en clonar el objeto con la informacion ya bajada y luego cambiarle esas pocas propiedades, optimizando asi la velocidad... ![]() Gracias a todos por las respuestas. ![]() P.D.: Perdon por tardar en responder, he estado ocupado esos dias. |
![]() |
|
|
![]() |
||||
Tema | Autor | Foro | Respuestas | Último mensaje |
¿cuál es mejor: "close" o "application.terminate"? | unreal4u | Varios | 5 | 05-03-2007 11:01:19 |
porque no me reconoce los caracteres "*" ni "%" cuando filtro | mrmago | Conexión con bases de datos | 10 | 27-01-2006 04:21:16 |
Compartir "objetos" entre varias instancias | mafebresv | Varios | 4 | 16-01-2006 23:38:23 |
Tipo de Variable."String" ó "Double" | UTECYBER | OOP | 7 | 15-12-2003 20:25:39 |
![]() |
|