Announcement

Collapse
No announcement yet.

Obtaining an unique copy of an object / interface

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Obtaining an unique copy of an object / interface

    To all,

    How can I have a copy of an object that doesn't point to the same reference (obj ptr).

    When I obtain a reference to an class which is stored in an array (of interface type e.g. iData)

    I get a reference to that object. Now, what I want is to have a copy, exactly the same as the reference but in a different address space. I have tried high and low but I can't seem to do except by ..

    CopyOfClass.property1 = original.property1
    CopyOfclass.Property2 = original.property2
    etc...

    This is not what I want.

    I would like to see

    Dim CopyOfClass as IData
    Dim OriginalData as IData

    CopyOfClass = Class "cData"

    CopyOfClass = OriginalData

    But it doesn't work apparently. Both Idata reference point to the same objptr
    Any ideas ?
    So here we are, this is the end.
    But all that dies, is born again.
    - From The Ashes (In This Moment)

  • #2
    I played around and implemented a method in the object that I need a copy of

    Code:
         method CopyInstance(ByVal TargetData As iData) As IData
    
            Local myField  As iData
            myfield = Class "cData"
    
            myDAta = TargetData
    
            method = myData
    
         End Method
    So here we are, this is the end.
    But all that dies, is born again.
    - From The Ashes (In This Moment)

    Comment


    • #3
      OOPS, this didn't work. I was being over-eager
      So here we are, this is the end.
      But all that dies, is born again.
      - From The Ashes (In This Moment)

      Comment


      • #4
        There is no simple way.
        In a language like c# you can implement 'serialization' aka streaming.
        Iow, there is no short-route, you'll need to create a new instance and then copy it's data over.
        hellobasic

        Comment


        • #5
          Dear Support,

          Please put on the wishlist a wish for a keyword in the sense of

          CopyInstanceOf

          Thank you !

          Steven Pringels
          So here we are, this is the end.
          But all that dies, is born again.
          - From The Ashes (In This Moment)

          Comment


          • #6
            That would not be possible for an object created externally.

            Comment


            • #7
              Bob,

              What about a class / interface which is not COM but a PB class ? If that would be doable please please please

              Cheers

              Steven
              So here we are, this is the end.
              But all that dies, is born again.
              - From The Ashes (In This Moment)

              Comment


              • #8
                Sounds like the Clone method of an enumerator, but that would not be an external object.
                Last edited by Dominic Mitchell; 12 Nov 2008, 03:22 PM.
                Dominic Mitchell
                Phoenix Visual Designer
                http://www.phnxthunder.com

                Comment


                • #9
                  Overloaded Assignment Operator (operator=)

                  What it sounds like you want is an overloaded assignment operator. In C++ one can define what the '=' sign means in the context of your class. For example, if you have two simple squares setting them equal to each other might be defined as setting the length of the 1st equal to the length of the 2nd, and ditto for the width. But you would have to have two squares to start with. Here is a C++ example without an overloaded assignment operator...

                  Code:
                  #include <stdio.h>
                  
                  class CBox
                  {
                   public:  //member functions
                   CBox();
                   CBox(unsigned int ln, unsigned int wd):m_length(ln), m_width(wd){}
                   ~CBox(){}
                  
                   unsigned int Area()
                   {
                    return m_length*m_width;
                   }
                  
                   public:  //member variables
                   unsigned int m_length;
                   unsigned int m_width;
                  };
                  
                  int main(void)
                  {
                   CBox bx1(3,4);
                   CBox bx2(6,8);
                  
                   printf("bx1.Area() = %u\n",bx1.Area());
                   printf("bx2.Area() = %u\n",bx2.Area());
                  
                   return 0;
                  }
                  
                  Output:
                  =========================
                  bx1.Area() = 12
                  bx2.Area() = 48
                  Here is the same program with the addition of the overloaded operator...

                  Code:
                  #include <stdio.h>
                  
                  class CBox
                  {
                   public:  //member functions
                   CBox();
                   CBox(unsigned int ln, unsigned int wd):m_length(ln), m_width(wd){}
                   ~CBox(){}
                  
                   unsigned int Area()
                   {
                    return m_length*m_width;
                   }
                  
                   unsigned int operator=(CBox another)   //sets member variables of object for which it is called
                   {                                   //with the values of object passed as parameter.
                    this->m_length=another.m_length;
                    this->m_width=another.m_width;
                  
                    return this->Area();
                   }
                  
                   public:  //member variables
                   unsigned int m_length;
                   unsigned int m_width;
                  };
                  
                  int main(void)
                  {
                   CBox bx1(3,4);
                   CBox bx2(6,8);
                  
                   printf("bx1.Area() = %u\n",bx1.Area());
                   printf("bx2.Area() = %u\n",bx2.Area());
                   bx1=bx2;                            // <<<< set bx1=bx2 will cause call of operator= overload
                   printf("bx1.Area() = %u\n",bx1.Area());
                  
                   return 0;
                  }
                  
                  /*
                  Output:
                  =========================
                  bx1.Area() = 12
                  bx2.Area() = 48
                  bx1.Area() = 48
                  Press any key to continue
                  */
                  I imagine the whole thing could be adequately simulated in PowerBASIC by creating a Method in your class which would take a parameter of the same type as the class itself and within the method you could minipulate the various data members as required by the needs of your program whether that be a member by member copy accross or whatever. You could call the method 'Equal' or 'Assign' or something. I've a few minutes. I'll see if I can 'easily' get it to work in PB!


                  Added 10 minutes later:

                  Yep! Worked without much ado. Hope this helps!
                  Code:
                  #Compile Exe  'Console Compiler 5.0
                  #Dim All
                  
                  Class CBox
                    Instance m_dblLength, m_dblWidth, m_dblHeight As Double
                  
                    Interface ICBox : Inherit IUnknown                'Can use Property Get/Set
                      Property Get Length() As Double                 'Methods to initialize
                        Property=m_dblLength                          'length, width, and
                      End Property                                    'height dimensions.
                  
                      Property Set Length(Byval dblLength As Double)
                        m_dblLength=dblLength
                      End Property
                  
                      Property Get Width() As Double
                        Property=m_dblWidth
                      End Property
                  
                      Property Set Width(Byval dblWidth As Double)
                        m_dblWidth=dblWidth
                      End Property
                  
                      Property Get Height() As Double
                        Property=m_dblHeight
                      End Property
                  
                      Property Set Height(Byval dblHeight As Double)
                        m_dblHeight=dblHeight
                      End Property
                  
                      Method MakeBox(dblLength As Double, dblWidth As Double, dblHeight As Double)
                        m_dblLength=dblLength                           'One can also create a
                        m_dblWidth=dblWidth                             'Method to set all the
                        m_dblHeight=dblHeight                           'sides all at once.
                      End Method
                  
                      Method Equal(bxAnother As ICBox)
                        m_dblLength = bxAnother.Length()
                        m_dblWidth  = bxAnother.Width()
                        m_dblHeight = bxAnother.Height()
                      End Method
                  
                      Method Volume() As Double                         'This member function
                        Method=m_dblLength * m_dblWidth * m_dblHeight   'will return the  gross
                      End Method                                        'volume of a box.
                    End Interface
                  End Class
                  
                  
                  Function PBMain() As Long
                    Local box1 As ICBox
                    Local box2 As ICbox
                    
                    Print "box1:"
                    Print "====================="
                    box1=Class "CBox"
                    box1.Length=3.0
                    box1.Width=4.0
                    box1.Height=5.0
                    Print "box1.Length = "box1.Length()
                    Print "box1.Width  = "box1.Width()
                    Print "box1.Height = "box1.Height()
                    Print "box1.Volume = "box1.Volume()
                    Print
                    
                    Print "box2:"
                    Print "====================="
                    box2=Class "CBox"
                    box2.Length=6.0
                    box2.Width=7.0
                    box2.Height=8.0
                    Print "box2.Length = "box2.Length()
                    Print "box2.Width  = "box2.Width()
                    Print "box2.Height = "box2.Height()
                    Print "box2.Volume = "box2.Volume()
                    Print
                    
                    box1.Equal(box2)
                    Print "box1:"
                    Print "====================="
                    Print "box1.Length = "box1.Length()
                    Print "box1.Width  = "box1.Width()
                    Print "box1.Height = "box1.Height()
                    Print "box1.Volume = "box1.Volume()
                    Print
                    Waitkey$
                  
                    PBMain=0
                  End Function
                  Output:
                  =============================
                  Code:
                  box1:
                  =====================
                  box1.Length =  3
                  box1.Width  =  4
                  box1.Height =  5
                  box1.Volume =  60
                  
                  box2:
                  =====================
                  box2.Length =  6
                  box2.Width  =  7
                  box2.Height =  8
                  box2.Volume =  336
                  
                  box1:
                  =====================
                  box1.Length =  6
                  box1.Width  =  7
                  box1.Height =  8
                  box1.Volume =  336
                  Last edited by Fred Harris; 12 Nov 2008, 08:07 PM. Reason: add comments
                  Fred
                  "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                  Comment


                  • #10
                    Hi Fred,

                    Thank you for investing the time to try this out. My guess was that this would
                    surely work since you're assigning the values from an instance to the instance
                    variables in the interface. What I'm seeking is what's called Clone functionality
                    without having to manually assign the property of Class 1 to Class 2.

                    Like

                    Dim Box1 as ICBox
                    Dim Box2 as ICBox

                    Box1 = Class "cBox"
                    Box2 = Class "cBox"


                    Box1.Length = 10
                    ...

                    and then

                    Box2 = CopyInstanceOf(Box1)

                    The CopyInstanceOf keyword (doesn't exist !!) would assign the properties
                    of Box1 To Box2 where Box2 has its own address space.

                    Consider it similar like assigning to 2 UDT which reside in a different memory
                    space but instead of UDT it would be done for classes.

                    anyway thanks again for your help.
                    So here we are, this is the end.
                    But all that dies, is born again.
                    - From The Ashes (In This Moment)

                    Comment


                    • #11
                      Imo it's barely possible to create a standard functionality.
                      Once the object to copy contains references to other objects you may be out of luck right away.

                      I think you'll need a simple custom procedure which copies the data into a newly created object instance.
                      Then decide what to do with specific scenario's.
                      hellobasic

                      Comment


                      • #12
                        A Copy Constructor Is What You Really Need

                        Where I differ with your thoughts Stephen is the desirability of making this functionality a part of the compiler. As Mr. Zale stated it wouldn't work. There simply is no way the compiler would be able to do anything more than a simple member by member copy of intrinsic basic data types such as longs, integers and so on. Don't forget that classes can also contain member variables that are themselves classes, and of course classes can inherit from base classes. What this points to is the fact that object instantiation/construction can become a complex affair in anything other than trivial cases such as exemplified by my square and box examples. This becomes the case quickly when memory allocations become necessary, for example.

                        The way this is handled in C++, which of course is pretty much the 900 pound gorilla of OOP languages, is through the concept of overloading class constructors. And this is just the class specific application of the broader concept of function overloading, which means that in that language one can have multiple functions of exactly the same name, but different parameter lists (and this makes for great fun with ‘unresolved externals’ in linking as a result of the name mangling C++ does to make this work!). Anyway, here is a C++ program showing three types of constructors. There is first a constructor for an uninitialized object, then a constructor for an initialized object, and finally, a copy constructor. And I made things interesting by adding a null terminated asciz string to the Cbox object as an additional member that is to contain a name of each box. Unlike with PowerBASIC where strings are handled by the compiler, in C++ if not using additional libraries one must deal with strings the old fashioned C way and do memory allocations. I did this to make my point that only in trivial cases can the compiler be expected to internally reproduce objects for you. Here is the program.

                        Code:
                        #include <stdio.h>
                        #include <string.h>
                        
                        class CBox
                        {
                         public:  //member functions
                         
                         CBox()   //Uninitialized Constructor
                         {
                          printf("Call Of Uninitialized Constructor!\n");
                          this->m_szStrBuffer=NULL;
                         };  
                        
                         CBox(unsigned int ln, unsigned int wd, char* szString) //Constructor For 
                         {                                                      //Full Initialization 
                          printf("Call Of Initialized Constructor!\n");         //Of Member Variables
                          m_length=ln;                                          
                          m_width=wd;
                          this->m_szStrBuffer=new char[strlen(szString)+1];
                          strcpy(this->m_szStrBuffer,szString);
                         }
                        
                         CBox(const CBox &another) //Copy Constructor For Initializing A class CBox
                         {                         //Object With Another
                          printf("Call Of Copy Constructor!\n");
                          this->m_length=another.m_length;
                          this->m_width=another.m_width;
                          this->m_szStrBuffer=new char[strlen(another.m_szStrBuffer)+1];
                          strcpy(this->m_szStrBuffer,another.m_szStrBuffer);
                         }
                         
                         ~CBox()  //Destructor
                         {
                          if(this->m_szStrBuffer)
                             printf("CBox Destructor For %s Called!\n",this->m_szStrBuffer);
                          else
                             printf("CBox Destructor For An Unidentifiable CBox Called!\n");
                          if(this->m_szStrBuffer)
                             delete[] this->m_szStrBuffer;
                         }
                        
                         unsigned int Area()
                         {
                          return m_length*m_width;
                         }
                        
                         public:       //member variables
                         unsigned int  m_length;
                         unsigned int  m_width;
                         char* m_szStrBuffer;
                        };
                        
                        int main(void)
                        {
                         CBox bx;
                         CBox bx1(3,4,"bx1");
                         CBox bx2(6,8,"bx2");
                         CBox bx3(bx2);
                        
                         printf("%s.Area()=%u\n",bx1.m_szStrBuffer,bx1.Area());
                         printf("%s.Area()=%u\n",bx2.m_szStrBuffer,bx2.Area());
                         printf("bx3.Area()=%u\n",bx3.Area());
                        
                         return 0;
                        }
                        
                        /*
                        Output:
                        =============================
                        1) Call Of Uninitialized Constructor!
                        2) Call Of Initialized Constructor!
                        3) Call Of Initialized Constructor!
                        4) Call Of Copy Constructor!
                        5) bx1.Area()=12
                        6) bx2.Area()=48
                        7) bx3.Area()=48
                        8) CBox Destructor For bx2 Called!
                        9) CBox Destructor For bx2 Called!
                        10)CBox Destructor For bx1 Called!
                        11)CBox Destructor For An Unidentifiable CBox Called!
                        */
                        The line CBox bx causes a call to the Uninitialized CBox Constructor which does nothing but set the m_szStrBuffer char pointer to NULL so the destruction of this object doesn't GPF. C and C++ are unlike PowerBASIC in that uninitialized variables can contain junk values, and the operation of the class destructor is predicated upon valid values being there. The line

                        CBox bx1(3,4,"bx1");

                        causes line 2 in the output to occur. The sides are set to 3 and 4 respectively, and the
                        string "bx1" is copied to a buffer allocated with C++'s 'new' operator, which is a memory
                        allocation mechanism. The line

                        CBox bx2(6,8,"bx2");

                        does similiar to the last and results in line 3 of the output. The last initialization, i.e.,

                        CBox bx3(bx2);

                        does what you want to happen for creating this thread, i.e., your thread topic, and shows the action of an implemented 'Copy Constructor', whose action prints line 4 of the output, as well as allocating memory to copy bx2's string to the new CBox object, i.e., bx3. Lines 5, 6, and 7 show the area of the three boxes, and note that bx3 is an exact copy of bx2. They are not pointers to the same object. bx3 had its own memory allocation in the copy constructor where the string in bx2's memory was copied to it. Finally, lines 8 through 11 of the output show the destruction of the objects in the reverse order of their creation.

                        The point here is to show that in creating a class its the implementor of the class' responsibility to ensure that objects are created correctly, in that, that person has to take whatever actions are necessary to create objects of that class, provide copy constructors if needed, and arrange for the destruction of objects. Only in the simplest cases could the compiler be given the responsibility for this.
                        Last edited by Fred Harris; 13 Nov 2008, 10:14 AM. Reason: forgot [] brackets on delete
                        Fred
                        "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                        Comment


                        • #13
                          This thread seems to be telling me that objects can't be cloned except by copying the original instance variables one at a time. Is this (still) the case?

                          To my very simple brain, making a clone of a PB object is a) quite likely to be required b) no more complicated than duplicating the instance variables.

                          Comment


                          • #14
                            I think we discussed this 2+ years ago. It is not possible to clone an object from outside the object. There's more to it than just some instance variables.

                            Bob

                            Comment


                            • #15
                              Code:
                              CLASS 
                                  INTERFACE 
                              
                                       METHOD CLONE  (param) 
                                         {your code here}
                              Michael Mattias
                              Tal Systems Inc. (retired)
                              Racine WI USA
                              [email protected]
                              http://www.talsystems.com

                              Comment


                              • #16
                                Originally posted by Bob Zale View Post
                                It is not possible to clone an object from outside the object.
                                Well, I can write code that does it, but with 100 instance variables it is a little time-consuming. If both the original and cloned objects exist in the same source module, surely there is nothing more to it than just some instance variables?

                                Of course! I can write an application to write the clone code. Why did I not think of that sooner.

                                OK I'm making an assumption - that only the instance variables for which get/set properties have been defined will be cloned. I design my objects as types then use my UDT2CLASS application to create the class and interface code from the type declaration, so I always have those properties defined. So it really isn't just the instance variables after all. But if I can write code to do it at the source code level, then I will take some convincing that the compiler can't do a better job of it.
                                Last edited by Chris Holbrook; 27 Jan 2011, 02:15 PM. Reason: added last paragraph

                                Comment


                                • #17
                                  Of course! I can write an application to write the clone code. Why did I not think of that sooner.
                                  Or just write a procedure to set those instance variables. You can use that procedure regardless of 'which' instance you are working with.

                                  > ..100 instance variables..

                                  Put em in an INSTANCE UDT. When cloning, copy the UDT.

                                  Or save 'em in an INSTANCE Array. When cloning, a three-line FOR..NEXT can copy 'em.
                                  Michael Mattias
                                  Tal Systems Inc. (retired)
                                  Racine WI USA
                                  [email protected]
                                  http://www.talsystems.com

                                  Comment


                                  • #18
                                    UDTs aren't much use with dynamic strings. Fortunately the UDT2Class doesn't care what the variable type is:
                                    Code:
                                    type mylunch
                                        avar as lobster
                                        bvar as horseradish
                                    end type
                                    Point, click, behold!

                                    Code:
                                    class mylunch
                                        instance avar as lobster
                                        instance bvar as horseradish
                                    
                                        class method create
                                        end method
                                        '
                                        class method destroy
                                        end method
                                        '
                                        interface mylunch0
                                            inherit iunknown
                                                property get avar() as lobster
                                                    property = avar
                                                end property
                                                '
                                                property set avar( byval in_avar as lobster)
                                                    avar = in_avar
                                                end property
                                                '
                                                property get bvar() as horseradish
                                                    property = bvar
                                                end property
                                                '
                                                property set bvar( byval in_bvar as horseradish)
                                                    bvar = in_bvar
                                                end property
                                                '
                                            end interface
                                        end class
                                    Doh! Now I can see another issue - if the instance var is an array, we need a way of exporting its bounds - another tweak to UDT2Class coming up....

                                    Comment


                                    • #19
                                      I've added a Clone method and bounds methods for any 1D instance variable array to the UDT2Class converter, see post #21 here

                                      I still think it should be done by the compiler.

                                      Comment


                                      • #20
                                        > still think it should be done by the compiler.

                                        Why should it?

                                        Heck, anyone who wants to do a 'clone' method can simply adapt the source code generously provided by... why, YOU !
                                        Michael Mattias
                                        Tal Systems Inc. (retired)
                                        Racine WI USA
                                        [email protected]
                                        http://www.talsystems.com

                                        Comment

                                        Working...
                                        X