Polymorphic assignment?

Discussion in 'C++' started by Mr. Ed, Aug 10, 2005.

  1. Mr. Ed

    Mr. Ed Guest

    I have a base class which has about 150 derived classes. Most of the
    derived classes are very similar, and many don't change the base class
    at all. All the derived classes have a unique factory method which
    returns a new object of the derived type.

    The problem I've got is that I now need to polymorphically clone a
    derived class object, but I don't want to write a separate 'clone'
    method for each of these 150 classes. Instead, I thought I might get
    away with just writing one base class clone routine instead, something
    like this pseudo-code:

    BaseClass BaseClass::clone() {
    BaseClass obj = this->factory(); // line 1
    obj = *this; // line 2
    return obj;
    }

    The rationale is that:

    (line 1) 'obj' is correctly created as a derived-class object, because
    'this->factory()' calls the polymorphic derived-class factory method

    (line 2) 'obj = *this' uses the default copy assignment operator in a
    given derived class to copy all the derived-class members to 'obj'.

    This doesn't work, however, because the compiler doesn't know which
    operator= to use in line 2. Basically, line 2 is asking for a
    polymorphic assignment.

    Is this code fixable? Is there any way to do this without writing 150
    clone routines?

    Thanks -

    Ed
     
    Mr. Ed, Aug 10, 2005
    #1
    1. Advertising

  2. Mr. Ed wrote:
    > I have a base class which has about 150 derived classes. Most of the
    > derived classes are very similar, and many don't change the base class
    > at all.


    Why do you have them, then?

    > All the derived classes have a unique factory method which
    > returns a new object of the derived type.


    What's its signature? Is it a static member function? If not, what
    object do you use to call your factory?

    > The problem I've got is that I now need to polymorphically clone a
    > derived class object, but I don't want to write a separate 'clone'
    > method for each of these 150 classes. Instead, I thought I might get
    > away with just writing one base class clone routine instead, something
    > like this pseudo-code:
    >
    > BaseClass BaseClass::clone() {
    > BaseClass obj = this->factory(); // line 1


    What does 'factory' return, an object? If so, how would you avoid
    slicing?

    > obj = *this; // line 2


    At this point 'obj' contains _no_ traces of the derived object 'factory'
    may have returned.

    > return obj;
    > }
    >
    > The rationale is that:
    >
    > (line 1) 'obj' is correctly created as a derived-class object, because
    > 'this->factory()' calls the polymorphic derived-class factory method


    But it immediately loses all traces of how it was created when you
    initialise the BaseClass object with it.

    > (line 2) 'obj = *this' uses the default copy assignment operator in a
    > given derived class to copy all the derived-class members to 'obj'.


    In what given derived class? 'obj' has the type BaseClass.

    > This doesn't work, however, because the compiler doesn't know which
    > operator= to use in line 2. Basically, line 2 is asking for a
    > polymorphic assignment.


    No, it doesn't. You need 'obj' to be either a reference or a pointer
    to invoke anything polymorphically. It can't be a reference because what
    would it be a reference of? It could be a pointer to a dynamic object.

    > Is this code fixable? Is there any way to do this without writing 150
    > clone routines?


    I don't know how your 'factory' method works, but it is most fitting to
    have it accept a "prototype":

    BaseClass* factory(BaseClass* proto = 0)
    {
    if (proto)
    return new Baseclass(*proto); // copy-construction
    else
    return new BaseClass(); // default-construction
    }

    This way you may need to create a parameterized constructor for each
    derived class to accept a reference to base. Whatever it does with it
    is only its own business.

    Another solution if your 'function' member actually returns a pointer
    to a new'ed object. Then polymorphic assignment is possible:

    virtual BaseClass& operator=(BaseClass const other&); // implement
    // as you see fit in derived


    BaseClass* clone() {
    BaseClass* pobj = this->factory();
    *pobj = *this; // this will invoke the virtual operator
    return pobj;
    }

    You will have to still implement operator=(BaseClass const&); in every
    derived class (similar to the parameterized constructor I wrote about
    earlier).

    V
     
    Victor Bazarov, Aug 10, 2005
    #2
    1. Advertising

  3. Mr. Ed

    Alipha Guest

    Mr. Ed wrote:
    > I have a base class which has about 150 derived classes. Most of the
    > derived classes are very similar, and many don't change the base class
    > at all. All the derived classes have a unique factory method which
    > returns a new object of the derived type.
    >
    > The problem I've got is that I now need to polymorphically clone a
    > derived class object, but I don't want to write a separate 'clone'
    > method for each of these 150 classes. Instead, I thought I might get
    > away with just writing one base class clone routine instead, something
    > like this pseudo-code:
    >
    > BaseClass BaseClass::clone() {
    > BaseClass obj = this->factory(); // line 1
    > obj = *this; // line 2
    > return obj;
    > }


    slice. obj is a BaseClass object, it will /always/ be a BaseClass
    object; it will /never/ be a derived class object. This initialization
    slices off the derived object's behavior when the /copy/ into the obj
    is made. Same goes for your return value of clone and factory. You need
    to be working with pointers (or references, but they don't apply here)
    if you expect polymorphic behavior.

    >
    > The rationale is that:
    >
    > (line 1) 'obj' is correctly created as a derived-class object, because
    > 'this->factory()' calls the polymorphic derived-class factory method
    >
    > (line 2) 'obj = *this' uses the default copy assignment operator in a
    > given derived class to copy all the derived-class members to 'obj'.
    >
    > This doesn't work, however, because the compiler doesn't know which
    > operator= to use in line 2. Basically, line 2 is asking for a
    > polymorphic assignment.
    >
    > Is this code fixable? Is there any way to do this without writing 150
    > clone routines?
    >
    > Thanks -
    >
    > Ed
     
    Alipha, Aug 10, 2005
    #3
  4. Mr. Ed

    Mr. Ed Guest

    Sorry guys -

    >BaseClass BaseClass::clone() {
    > BaseClass obj = this->factory(); // line 1
    > obj = *this; // line 2
    > return obj;
    >}


    I over-simplified my code too much; the factory method returns a smart
    pointer to the derived object, and 'obj' is of a smart pointer type. A
    better summary would have been:

    SP_BaseClass BaseClass::clone() {
    SP_BaseClass obj = this->factory(); // line 1
    obj = *this; // line 2
    return obj;
    }

    So, there's no slicing problem in line 1.

    On Wed, 10 Aug 2005 13:57:55 -0400, Victor Bazarov
    <> wrote:

    >Mr. Ed wrote:
    >> I have a base class which has about 150 derived classes. Most of the
    >> derived classes are very similar, and many don't change the base class
    >> at all.

    >
    >Why do you have them, then?


    Long story, but basically to have a heterogeneous tree of these
    classes rather than a homogeneous tree.

    > > All the derived classes have a unique factory method which
    >> returns a new object of the derived type.

    >
    >What's its signature? Is it a static member function? If not, what
    >object do you use to call your factory?


    static member function in each derived class:

    class derived_x {
    ...
    static RefType factory(void) { return RefType(new(derived_x)); }
    };

    where 'RefType' is a reference-counted smart ptr type.

    I'm just working through the rest of your comments. At first sight, it
    seems that either I have to use your suggestion of a custom assignment
    operator in each derived class, or a custom clone method in each
    derived class, which means that I have to add a lot of lines of text
    which are basically redundant... :(

    Cheers

    Ed
     
    Mr. Ed, Aug 10, 2005
    #4
  5. Mr. Ed wrote:
    >[...]
    >>>All the derived classes have a unique factory method which
    >>>returns a new object of the derived type.

    >>
    >>What's its signature? Is it a static member function? If not, what
    >>object do you use to call your factory?

    >
    >
    > static member function in each derived class:
    >
    > class derived_x {


    class derived_x : public base {

    > ...
    > static RefType factory(void) { return RefType(new(derived_x)); }
    > };


    And how the hell can you call the right one (supposedly one in a derived
    class) from a base class member function 'clone'? There is no way. You
    need a polymorphic factory.

    > where 'RefType' is a reference-counted smart ptr type.
    >
    > I'm just working through the rest of your comments. At first sight, it
    > seems that either I have to use your suggestion of a custom assignment
    > operator in each derived class, or a custom clone method in each
    > derived class, which means that I have to add a lot of lines of text
    > which are basically redundant... :(


    Nobody said life was easy... Not it this thread, anyway.

    V
     
    Victor Bazarov, Aug 10, 2005
    #5
  6. Mr. Ed

    Mr. Ed Guest

    On Wed, 10 Aug 2005 14:34:21 -0400, Victor Bazarov
    <> wrote:

    >Mr. Ed wrote:
    > >[...]
    >>>>All the derived classes have a unique factory method which
    >>>>returns a new object of the derived type.
    >>>
    >>>What's its signature? Is it a static member function? If not, what
    >>>object do you use to call your factory?

    >>
    >>
    >> static member function in each derived class:
    >>
    >> class derived_x {

    >
    >class derived_x : public base {
    >
    >> ...
    >> static RefType factory(void) { return RefType(new(derived_x)); }
    >> };

    >
    >And how the hell can you call the right one (supposedly one in a derived
    >class) from a base class member function 'clone'? There is no way. You
    >need a polymorphic factory.


    It is polymorphic. The base class has a virtual factory method; the
    derived classes over-ride it with a static member. I'm assuming that
    in line 1:

    BaseClass BaseClass::clone() {
    BaseClass obj = this->factory(); // line 1
    ...
    }

    the correct derived class is called. Are you saying that this is
    wrong?

    Cheers

    Ed
     
    Mr. Ed, Aug 10, 2005
    #6
  7. Mr. Ed wrote:

    > On Wed, 10 Aug 2005 14:34:21 -0400, Victor Bazarov
    > <> wrote:
    >
    >
    >>Mr. Ed wrote:
    >>
    >>>[...]
    >>>
    >>>>>All the derived classes have a unique factory method which
    >>>>>returns a new object of the derived type.
    >>>>
    >>>>What's its signature? Is it a static member function? If not, what
    >>>>object do you use to call your factory?
    >>>
    >>>
    >>>static member function in each derived class:
    >>>
    >>>class derived_x {

    >>
    >>class derived_x : public base {
    >>
    >>
    >>> ...
    >>> static RefType factory(void) { return RefType(new(derived_x)); }
    >>>};

    >>
    >>And how the hell can you call the right one (supposedly one in a derived
    >>class) from a base class member function 'clone'? There is no way. You
    >>need a polymorphic factory.

    >
    >
    > It is polymorphic. The base class has a virtual factory method; the
    > derived classes over-ride it with a static member.


    WHAT???

    > I'm assuming that
    > in line 1:
    >
    > BaseClass BaseClass::clone() {
    > BaseClass obj = this->factory(); // line 1
    > ...
    > }
    >
    > the correct derived class is called. Are you saying that this is
    > wrong?


    Uh... Wrong? How should I break it to you?... You simply cannot
    override a virtual member function with a static one. Otherwise, no,
    it's not wrong.

    V
     
    Victor Bazarov, Aug 10, 2005
    #7
  8. Mr. Ed

    Axter Guest

    Mr. Ed wrote:
    > I have a base class which has about 150 derived classes. Most of the
    > derived classes are very similar, and many don't change the base class
    > at all. All the derived classes have a unique factory method which
    > returns a new object of the derived type.
    >
    > The problem I've got is that I now need to polymorphically clone a
    > derived class object, but I don't want to write a separate 'clone'
    > method for each of these 150 classes. Instead, I thought I might get
    > away with just writing one base class clone routine instead, something
    > like this pseudo-code:
    >
    > BaseClass BaseClass::clone() {
    > BaseClass obj = this->factory(); // line 1
    > obj = *this; // line 2
    > return obj;
    > }
    >
    > The rationale is that:
    >
    > (line 1) 'obj' is correctly created as a derived-class object, because
    > 'this->factory()' calls the polymorphic derived-class factory method
    >
    > (line 2) 'obj = *this' uses the default copy assignment operator in a
    > given derived class to copy all the derived-class members to 'obj'.
    >
    > This doesn't work, however, because the compiler doesn't know which
    > operator= to use in line 2. Basically, line 2 is asking for a
    > polymorphic assignment.
    >
    > Is this code fixable? Is there any way to do this without writing 150
    > clone routines?


    I recommend using the following clone smart pointer class:
    http://code.axter.com/clone_ptr.h

    The above clone smart pointer, does not need a clone method. It can
    correctly duplicate the correct derived copy of itself through the
    assignment operator.
    Example code:
    void CopyCorrectDerivedTypeDemo()
    {
    std::vector<clone_ptr<BaseClass> > vBaseClass;
    //Setup data using base and derived type classes
    vBaseClass.push_back(new BaseClass( "3" ));
    vBaseClass.push_back(new Derived_B( "2" ));
    vBaseClass.push_back(new BaseClass( "1" ));
    vBaseClass.push_back(new Derived_A( "5" ));
    vBaseClass.push_back(new BaseClass( "4" ));

    //Copy contents from one container to another
    std::vector<clone_ptr<BaseClass> > vBaseClass_Copy(vBaseClass.begin(),
    vBaseClass.end());

    //Display results
    for (int i = 0;i < vBaseClass_Copy.size();++i)
    {
    vBaseClass_Copy->WhoAmI();
    }
    In above example code, the vBaseClass_Copy container gets the correct
    dervied copy from the vBaseClass container.
    This smart pointer does not share the pointer, and instead has strict
    pointer ownership.
     
    Axter, Aug 11, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Manco

    can webmethods be polymorphic?

    Manco, Feb 3, 2005, in forum: ASP .Net
    Replies:
    1
    Views:
    326
    Lionel LASKE
    Feb 3, 2005
  2. Thomas Britton

    polymorphic behaviour from class constant

    Thomas Britton, May 1, 2004, in forum: Java
    Replies:
    1
    Views:
    337
    Chris Uppal
    May 2, 2004
  3. Khanh  Le

    polymorphic question

    Khanh Le, May 2, 2004, in forum: Java
    Replies:
    3
    Views:
    400
    Tim Van Wassenhove
    May 2, 2004
  4. nagy
    Replies:
    36
    Views:
    1,015
    Terry Reedy
    Jul 20, 2006
  5. Chris
    Replies:
    34
    Views:
    1,535
Loading...

Share This Page