mccarthy@well.sf.ca.us (Patrick McCarthy) (06/27/90)
Given a pointer to a base type, what is the best way to copy the object
pointed to (bearing in mind that it may actually point to an object of a
derived type)?
In other words, suppose you have a class called Base, and two classes
Derived_1 and Derived_2 which inherit from Base. Suppose further that p
and q are of type Base *. In order to make p point to a copy of q using
q's copy constructor, you would have know q's type in advance as
follows:
p = (Base *) new Derived_2(q);
I am searching for a solution which does not require knowlege of the
type of the object being copied.
The best way I can think of to do this is to define a virtual function,
Base *Base::CloneSelf(), in the base class. This function would then be
overridden by all inherited classes. The wierdism here is that in order
to override the function, Derived_1::CloneSelf() would have to return
a pointer of type Base *.
It seems as though there should be a better way of doing this. Any and
all suggestions are welcome (as long as they're _constructive_ - pun
intended :-)
Thanks!
------------------------------------------------------------------------
Pat McCarthy
mccarthy@well.uucp
".signature? I ain't got to show you no stinking .signature!"dsr@luke.mitre.org (Douglas S. Rand) (06/27/90)
Copying objects is lots of fun. You can consider a few problems/options.
1) Do subobject pointers get copied? or do the subobjects get duplicated and
the new pointer assigned?
2) How do you handle method combination? Is each class responsible for
the entire
copy or does a child class ask its parent to copy the parent's data
(note that this
involves the extra bookeeping of explicitly calling the parent
method (as AT&T won't
admit that a symbol indicating 'super' is worth it).
3) Do you really want an exact copy? Maybe some instance vars need to
be individual
(like numerical identifiers).
etc. etc. etc.
In any case, use a virtual function for each class in the hierarchy and
use a consistent
style. You probably don't want to just duplicate the object. This is,
BTW, why C++
doesn't provide a simple copy function (neither does CLOS in CommonLISP,
and I
can't remember whether St80 does).
Douglas S. Rand
Internet: <dsrand@mitre.org>
Snail: MITRE, Burlington Road, Bedford, MA
Disclaimer: MITRE might agree with me - then again...kgorlen@sparkler.dcrt.nih.gov (Keith Gorlen) (06/28/90)
In article <18753@well.sf.ca.us>, mccarthy@well.sf.ca.us (Patrick McCarthy) writes: |>Given a pointer to a base type, what is the best way to copy the object |>pointed to (bearing in mind that it may actually point to an object of a |>derived type)? You might take a look at how the NIH Class Library implements the shallowCopy() and deepCopy() member functions. Basically, each class X defines the virtual function Object* X::shallowCopy() const { return new X(*this); } which will create a shallow copy of an X object by using the copy constructor for class X. Object::deepCopy() is a non-virtual member function that first uses shallowCopy() to make a shallow copy of an object, then invokes the virtual member function deepenShallowCopy(). Each class that has member variables that are pointers to objects or class instances implements deepenShallowCopy() to convert the shallow copy to a deep copy by applying deepenShallowCopy() recursively to the pointers and objects it contains. All this is described in detail in Section 7.3 of our new book "Data Abstraction and Object-Oriented Programming in C++", John Wiley & Sons, ISBN 047192346X. (I understand the first copies are probably running off the presses as I type.) The software is available via anonymous FTP in the file pub/nihcl.tar.Z on host alw.nih.gov (128.231.128.251). Keith Gorlen phone: (301) 496-1111 Building 12A, Room 2033 uucp: uunet!nih-csl!kgorlen National Institutes of Health Internet: kgorlen@alw.nih.gov Bethesda, MD 20892
ericg@ucschu.ucsc.edu (Eric Goodman) (07/03/90)
In article <18753@well.sf.ca.us> mccarthy@well.sf.ca.us (Patrick McCarthy) writes: > In other words, suppose you have a class called Base, and two classes > Derived_1 and Derived_2 which inherit from Base. Suppose further that p > and q are of type Base *. In order to make p point to a copy of q using > q's copy constructor, you would have know q's type in advance as > follows: A virtual overloaded operator= should work (I'm assuming that virtual operators are legal); the problem is that you would have to define it backwards: Class Base{ public: virtual Base operator=(Base) { ... } }; insures that the left operand of the = is of the correct type, so *p=*q; // could be used to copy *p into *q with p's type insured. I don't see how you could do this to copy in the ordinary fashion, though so this may be useless. Eric Goodman Humanities Division University of California, Santa Cruz ericg@ucschu.ucsc.edu ericg@ucschu.bitnet Eric_Goodman.staff@macmail.ucsc.edu ...!ucbvax!ucscc!ucschu!ericg
jimad@microsoft.UUCP (Jim ADCOCK) (07/04/90)
In article <4853@darkstar.ucsc.edu> ericg@ucschu.ucsc.edu (Eric Goodman) writes: >A virtual overloaded operator= should work (I'm assuming that virtual >operators are legal); Virtual overloaded operators are legal -- except operators new and delete. This is all neatly summerized in a table on page 306 of ARM. Interestingly, operator= has the unique characteristic of being virtual but not inherited! Can someone explain what this is suppose to mean? -- When I try the example below on my local compilers, it appears that virtual B& B::operator=(const B&) *is* being inherited. ??? extern "C" { #include "stdio.h" } class B { public: virtual B& operator=(const B&); }; B& B::operator=(const B&) { static int i=0; printf("%lX B::op=\n", (long)&i); return *this; } class D : public B { public: int i; }; main() { B& b1 = *new B; B& b2 = *new B; D& d1 = *new D; D& d2 = *new D; b1 = b1; d1 = d2; b1 = d1; }
steve@taumet.com (Stephen Clamage) (07/05/90)
In article <55612@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: >Interestingly, operator= has the unique characteristic of being >virtual but not inherited! Can someone explain what this is suppose >to mean? If a derived class inherits an operator=, what happens to the extra fields in the derived class? If the programmer goes to the trouble of writing operator=, the compiler must assume that something special, beyond memberwise assignment, is required. The compiler cannot guess what this is, so leaves it to the programmer. Hence, operator= is not inherited. (We could argue that if the derived class has no data members it is OK to inherit the operator=, but it is simpler to go with the ARM and say it is not inherited.) Virtual is a separate concept, and a virtual operator= merely assures that the correct operator is called in the case of polymorphic objects. The ARM states that the default operator= (memberwise assignment) is generated if (among other things) its address is taken. If a derived class needs a virtual operator= and the programmer does not declare one, the compiler should generate the default version and put it in the virtual table. If this didn't happen, it may be a bug in the compiler, or a compiler written to an earlier version of C++. -- Steve Clamage, TauMetric Corp, steve@taumet.com
jimad@microsoft.UUCP (Jim ADCOCK) (07/05/90)
In article <304@taumet.com> steve@taumet.UUCP (Stephen Clamage) writes: |In article <55612@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: |>Interestingly, operator= has the unique characteristic of being |>virtual but not inherited! Can someone explain what this is suppose |>to mean? .... |The ARM states that the default operator= (memberwise assignment) is |generated if (among other things) its address is taken. If a derived |class needs a virtual operator= and the programmer does not declare one, |the compiler should generate the default version and put it in the |virtual table. If this didn't happen, it may be a bug in the compiler, |or a compiler written to an earlier version of C++. Look at the example again. The compiler should only generate a default operator= of the form D& D::operator=([const] D&). But the virtual function whose template to be matched is B& D::operator=(const B&). So presumably, a compiler should, in the special case of virtual operator=, give a compile time squawk if B& D::operator=(const B&) isn't explicitly defined in every subclass D of B ? [The compiler I tried this example on erroneously allowed D to inherit B& B::operator=(const B&) via the vtable] Still doesn't answer my question though -- what is this suppose to *mean* ???