[comp.lang.c++] QUESTION: calling appropriate copy constructor

haskell@janus.Berkeley.EDU (Paul Haskell) (08/12/90)

Does anyone have useful insight on the following question?

Here is our (simplified) situation...

One of our applications has a base class "video_obj" and
derived classes "bitmap", "graphics",  and "text".
We have a list of pointers to video_obj called "list_elems"; the actual
pointed-to objects may be of any of the derived types.

We would like to be able to make copies of the list's members.
To make a copy, currently we find the list entry we wish to duplicate
with something like:

    int j = 0;
    while((j < list_length)&&(win_id_to_match != list_elems[j].win_id))
    {
      j++;
    }
    if (win_id_to_match == list_elems[j].win_id)
    {
       ...  ...
    }

(So, our method of deciding which list element to copy has nothing to do
with the actual type of the list element.)

Presumably for "... ..." we have to call either
  "new_pointer = new bitmap(list_elems[j])",
  "new_pointer = new graphics(list_elems[j])", or
  "new_pointer = new text(list_elems[j])"
depending on the derived type of "list_elems[j]".

So, here is the question:   Is there a cleaner way of deciding which
constructor to call other than
1)  adding a virtual function "return_type()" to video_obj and its
    derived classes that returns the actual type of the object
2)  switch()'ing on list_elems[j].return_type()  ?

The problem with this method is that when new derived classes are
designed, the designer has to remember to add the virtual return_type()
function with a unique return-value AND to modify the switch() to
contain another "new derived_class(list_elems[j])" statement.

Thanks very much for any suggestions.

Paul

brucec@phoebus.phoebus.labs.tek.com (Bruce Cohen;;50-662;LP=A;) (08/16/90)

In article <38098@ucbvax.BERKELEY.EDU> haskell@janus.Berkeley.EDU (Paul Haskell) writes:
> 
> Does anyone have useful insight on the following question?
>
> Here is our (simplified) situation...
> 
> One of our applications has a base class "video_obj" and
> derived classes "bitmap", "graphics",  and "text".
> We have a list of pointers to video_obj called "list_elems"; the actual
> pointed-to objects may be of any of the derived types.
> 
> We would like to be able to make copies of the list's members.
> To make a copy, currently we find the list entry we wish to duplicate
> with something like:
> 
>     int j = 0;
>     while((j < list_length)&&(win_id_to_match != list_elems[j].win_id))
>     {
>       j++;
>     }
>     if (win_id_to_match == list_elems[j].win_id)
>     {
>        ...  ...
>     }
> 
> (So, our method of deciding which list element to copy has nothing to do
> with the actual type of the list element.)
> 
> Presumably for "... ..." we have to call either
>   "new_pointer = new bitmap(list_elems[j])",
>   "new_pointer = new graphics(list_elems[j])", or
>   "new_pointer = new text(list_elems[j])"
> depending on the derived type of "list_elems[j]".
> 
> So, here is the question:   Is there a cleaner way of deciding which
> constructor to call other than
> 1)  adding a virtual function "return_type()" to video_obj and its
>     derived classes that returns the actual type of the object
> 2)  switch()'ing on list_elems[j].return_type()  ?
> 
> The problem with this method is that when new derived classes are
> designed, the designer has to remember to add the virtual return_type()
> function with a unique return-value AND to modify the switch() to
> contain another "new derived_class(list_elems[j])" statement.
> 
> Thanks very much for any suggestions.
> 
> Paul

Unless I'm misunderstanding your problem, it seems to me there's an easy
solution.  Add a virtual copy function to Class video_obj (I assume that
video_obj is an abstract class, so it can be a pure virtual function here),
then redefine it in each derived class to return a new object of the
derived class created by an X(const X&) copy constructer.  The only
drawback of this approach is that all the functions will have the return
type video_obj&, but that's implicit in your method too.  Note that I've
defined functions which return pointers, as in your examples, though you
could define the return types as references, to make copying in expressions
easy.  You might also want to define your own copy constructor, if there
are objects pointed to by these objects which need to be copied (a
DeepCopy, as opposed to a ShallowCopy).

defined like so:

class video_obj
{
    // ... stuff ...
  public:
    virtual video_obj* Copy() = 0;
}

class bitmap : public video_obj
{
    // ... stuff ...
  public:
    virtual video_obj* Copy();
}

video_obj* bitmap::Copy()
{
    return (video_obj*)(new bitmap(*this)); // cast not syntactically necessary
}

and so on for other classes derived from video_obj.

and it would be used like so:

video_obj* new_pointer = list_elems[j]->Copy();

---------------------------------------------------------------------------
NOTE: USE THIS ADDRESS TO REPLY, REPLY-TO IN HEADER MAY BE BROKEN!
Bruce Cohen, Computer Research Lab        email: brucec@tekcrl.labs.tek.com
Tektronix Laboratories, Tektronix, Inc.                phone: (503)627-5241
M/S 50-662, P.O. Box 500, Beaverton, OR  97077

--
---------------------------------------------------------------------------
NOTE: USE THIS ADDRESS TO REPLY, REPLY-TO IN HEADER MAY BE BROKEN!
Bruce Cohen, Computer Research Lab        email: brucec@tekcrl.labs.tek.com
Tektronix Laboratories, Tektronix, Inc.                phone: (503)627-5241
M/S 50-662, P.O. Box 500, Beaverton, OR  97077