Copy Object to a New Object
BlitzMax Forums/BlitzMax Beginners Area/Copy Object to a New Object
| ||
Hi All, Is there a command to copy one object to another object? If I do this: Type TFoo Field test$ End Type Local foo:TFoo = New TFoo foo.test = "FOO" Local bar:TFoo = foo bar.test = "BAR" Print foo.test Print bar.test Both prints out "BAR"... as it is coping by reference. I want both objects to be a different instance of each other, whilst keeping all the data. Please help. Cheers! |
| ||
You have to do the copy yourself. Make a new object and copy over all of the fields. There may be a way using reflection to get an object to copy itself, but I have not played with it yet. |
| ||
Thanks TaskMaster... Looking at my code again, and I'm now not sure what the problem is, I thought it was this. Ive got a set of buildings each with a set of slots, my problem is that if I click on one building it sets the slot of each building with that type. Eg 3 buildings, 2 houses and 1 bar. If I click the first house, the slots in both houses are used...!?!? I just want the building I clicked on! Here is a simplified version of my code: I thought of adding the following to TBuildingInfo: Method clone:TBuildingInfo() Local b:TBuildingInfo = New TBuildingInfo b.name = name b.slots = slots b.buildinginfoList = buildingInfoList Return b End Method and assigning like this: Local houseInfo:TbuildingInfo = infoList.Find("HOUSE") b.info = houseInfo.clone() But I still have the problem... any ideas? Thanks! |
| ||
Okay I think I found my problem... and it was that one object (TSlot) was still getting copied by reference... I did this in TBuildingInfo: Method clone:TBuildingInfo() Local b:TBuildingInfo = New TBuildingInfo b.name = name b.slots = New TSlotList For Local s:TSlot = EachIn slots Local sl:TSlot = b.slots.clone(s, slots) b.slots.AddSlot(sl.x,sl.y) Next b.buildinginfoList = buildingInfoList Return b End Method And added clone to TSlotList: Method clone:TSlot(s:TSlot, sl:TSlotList ) Local ss:TSlot = s.clone(sl) Return ss End Method Finally added clone to TSlot: Method clone:TSlot(sl:TSlotList ) Local s:TSlot = New TSlot s.x = x s.y = y s.empty = empty s.slotList = sl Return s End Method The working code: This is all when and good for objects with a small number of fields, but my proper TBuildingInfo has 40 fields ATM and will be more soon! Is there a smaller/simpler way to do this? |
| ||
I'm back again! Found this post http://www.blitzbasic.com/Community/posts.php?topic=73573#822043 by Azathoth and it looks like it might work... I guess this is how you use the metadata tags(?): Type TBuildingInfo Field name$ {Clone} Field slots:TSlotList{Clone} Field buildingInfoList:TBuildingInfoList {Clone} End Type And assign them by: b = buildings.AddNew(100,100, "HOUSE") Local houseInfo:TbuildingInfo = infoList.Find("HOUSE") b.info = TBuildingInfo(CloneObject(houseInfo)) This looks like it works for the name$ field, but still slots:TSlotList is still by reference... any ideas? Cheers |
| ||
I think there might be a way to memcopy the objects directly, but I'm not sure how to do this. |
| ||
I think there might be a way to memcopy the objects directly Not advisable, me thinks. |
| ||
You have to create a new slot list, and re-add each object in the list (if you want the same objects in the list). If you want the objects in the list to also be copies, you will have to copy them as well. |
| ||
Yes. There are 2 ways you can think of copying : A basic copy, which in effect creates a new objects and populates it with the objects the original contains. Those objects will be the same instances. A deep copy, which will create new copies of ALL objects. If you have a TList field, it would create a new TList, and new instances of all objects inside that list. The second form is obviously a lot more intensive, since it potentially has a lot of work to do. It all depends how much you need copied? Just the object you are dealing with, or all the objects it uses? My persistence module can do "proper" deep copying, albeit in a roundabout way - it converts the object-structure into XML, which you can then de-serialise to get a whole new set of objects. (i.e. it's designed for snap-shots of your objects for persisting on Disk, rather than on-the-fly copying). |
| ||
Thanks for the replies guys. @Czar Flavius - Ive read that doing the memcopy can really mess up the GC, especially if you have got objects within objects. @TaskMaster, looks like your right... Azathoth CloneObject function doesnt like to copy the TSlotList field (I kept getting null pointers!? when trying to {Clone} it)...so here is what Ive come up with: TBuildingInfo (notice the NoClone on the lists) Type TBuildingInfo Field name$ {Clone} Field slots:TSlotList{NoClone} Field buildingInfoList:TBuildingInfoList {NoClone} Method clone:TBuildingInfo() Local b:TBuildingInfo = TBuildingInfo (CloneObject(Self)) b.slots = New TSlotList For Local s:TSlot = EachIn Self.slots Local ss:TSlot = s.clone(slots) b.slots.AddSlot(ss.x,ss.y) Next b.buildingInfoList = Self.buildingInfoList Return b End Method End Type And to create the clone: Local buildings:TBuildingList = New TBuildingList ' create the global building list Local b:TBuilding b = buildings.AddNew(100,100, "HOUSE") ' create a new building and add it to the list Local houseInfo:TbuildingInfo = infoList.Find("HOUSE") 'get the data for the building b.info = houseinfo.clone() ' create a new copy of the data and assign it to the new building b.info.name = "1st House" ' check to see if the clone has worked Here is the full code: @Brucey, thanks for the info - Ill have a look at your persistence module - sounds interesting... |
| ||
@TaskMaster, looks like your right... Azathoth CloneObject function doesnt like to copy the TSlotList field (I kept getting null pointers!? when trying to {Clone} it) I think that has to do with {Clone} only affecting that specific field and not TSlotList's fields (it extends TList which doesn't contain the {Clone} metadata).Edit: This was to prevent lock ups when trying to clone cyclic references. |