Topic: assignment under derivation -> rules too complex ?
Author: herman@cs.kuleuven.ac.be (Herman Moons)
Date: Wed, 22 Apr 1992 16:47:27 GMT Raw View
I have a problem with the rules specified for assignment under derivation.
The rules state that if a derived class provides an assignment operator,
that operator is used when assigning derived classes to each other.
I have no problem with that, but the rules further state that assignment of
the base class parts becomes the responsibility of the derived class.
Consider the following hierarchy:
struct X {
int x;
void operator= (const X&);
};
void X::operator= (const X& xx) { x = xx.x; }
struct Y : public X {
int y;
};
struct Z : public Y {
int z;
void operator= (const Z&);
}
void Z::operator= (const Z& zz) { z = zz.z; }
...
Y y1, y2;
y1 = y2;
This works as expected, because by default memberwise assignment is used,
and the operator= for the base class part gets called.
Now for the strange part:
...
Z z1, z2;
z1 = z2;
Now operator= of Z gets called, but the base class parts are not assigned to
each other (under the current rules).
This seems strange to me. Since Y's are correctly assigned, why is this no
longer true for the Y parts of a Z ? Why do I have to bother with explicitly
assigning the base class parts to each other ?
Wouldn't it be simpler to simplify the rules as follows:
When assigning objects to each other, the class operator= is used. For
each base class part, the corresponding base class operator= is used for
the assignment.
When no user-defined operator= is provided, by default, memberwise
assingnment is used to assign class members to each other.
Such a rule seems more intuitive to me.
The same remarks go for intialization constructors.
Any comments on this ??
herman
-----------------------------------------------------------------------------
Herman Moons Katholieke Universiteit Leuven
Dept. of Computer Science
Tf : +32 (16) 20.10.15 ext 3642 Celestijnenlaan 200A
Fax: +32 (16) 20.53.08 B-3001 Heverlee-Leuven
Belgium
e-mail: herman@cs.kuleuven.ac.be
-----------------------------------------------------------------------------
Author: sakkinen@jyu.fi (Markku Sakkinen)
Date: 23 Apr 92 06:30:25 GMT Raw View
In article <1992Apr22.164727.3753@kulcs.uucp> herman@cs.kuleuven.ac.be (Herman Moons) writes:
>I have a problem with the rules specified for assignment under derivation.
>The rules state that if a derived class provides an assignment operator,
>that operator is used when assigning derived classes to each other.
>I have no problem with that, but the rules further state that assignment of
>the base class parts becomes the responsibility of the derived class.
>Consider the following hierarchy:
> [example deleted]
> ...
>Wouldn't it be simpler to simplify the rules as follows:
>
> When assigning objects to each other, the class operator= is used. For
> each base class part, the corresponding base class operator= is used for
> the assignment.
> When no user-defined operator= is provided, by default, memberwise
> assingnment is used to assign class members to each other.
>
>Such a rule seems more intuitive to me.
>The same remarks go for intialization constructors.
>
>Any comments on this ??
Let a well-known adversary of C++ defend it this time.
In C++ and almost all object-oriented languages, when an inherited operation
in overridden (redefined) in a subclass, the overriding is _total_
instead of incremental: if the functionality of the superclass operation
is needed, the subclass operation must invoke it explicitly.
-- BETA is an interesting exception: total overriding is never possible.
In Flavors and CLOS, some method combinations achieve incremental
redefinition.
It would be very unorthogonal if assignment operators were an exception
to the principle of total overriding. The default operator is only
a convenience feature for the most common case. When a class designer
wants to write an explicit assignment operator, he/she might in some
cases not even _want_ all superclass parts to be automatically assigned!
Constructors, on the other hand, _are_ already a special case,
by necessity. For them your wish is fulfilled: if all base classes
have constructors that don't necessarily require arguments,
you need not specify them at all in the constructor(s) of the derived class.
----------------------------------------------------------------------
Fight against terrorism: destroy the army HQ in Belgrade!
Markku Sakkinen (sakkinen@jytko.jyu.fi)
SAKKINEN@FINJYU.bitnet (alternative network address)
Department of Computer Science and Information Systems
University of Jyvaskyla (a's with umlauts)
PL 35
SF-40351 Jyvaskyla (umlauts again)
Finland
----------------------------------------------------------------------
Author: wicklund@intellistor.com (Tom Wicklund)
Date: 23 Apr 92 17:50:32 GMT Raw View
A very good reason to have a derived class handle assignment is that
the derived class may treat the base class as something other than a
member to be modified.
For example, some implementations of a string class implement
substrings as a class derived from a string. This simplifies the
implementation since a substring can be used whereever a string can be
used (reducing the number of member functions). However, string
assignment (s1 = s2) involves copying the text in s2 to s1 in some
manner. Substring assignment (substring = string) involves editing
whatever parent string the substring is refering to.
In implementations of this sort the string and substring are often
defined something like:
class string {
char *text;
int length;
// members functions...
};
class substring : public string {
string *parent; // string this refers to
int offset; // offset of substring text into parent's text.
// the string::text member points to parent->text+offset.
// the string::length member is the substring's length.
// members functions...
};
A string assignment looks something like the following (this example
isn't strictly correct but gives the general idea):
string& string::operator=(string& s)
{
// free old text in *this.
text = new char[s.length()];
memcpy(text, s.text);
length = s.length;
}
Substring assignment looks something like:
substring& substring::operator=(string& s)
{
// edit parent->text to insert s.text in place of
// parent(offset, length).
}
If substring assignment first executed string assignment then
substring could not be derived from string since the string assignment
would incorrectly free its text member (which points into the middle
of a parent text object). Or the parent string class would have to be
made more complex so that it knew when it was really being part of a
substring object and so should perform assignment differently.
If the base class should first be assigned then assignment can be
implemented as:
XX::operator=(XX& x)
{
this->XXparent::operator=(x);
// derived class manipulations.
}
Author: jimad@microsoft.com (Jim ADCOCK)
Date: 23 Apr 92 22:37:13 GMT Raw View
In article <1992Apr22.164727.3753@kulcs.uucp> herman@cs.kuleuven.ac.be (Herman Moons) writes:
|I have a problem with the rules specified for assignment under derivation.
|The rules state that if a derived class provides an assignment operator,
|that operator is used when assigning derived classes to each other.
|I have no problem with that, but the rules further state that assignment of
|the base class parts becomes the responsibility of the derived class.
Are these in fact "the rules" ? I've heard various people state differingly
what the rules are. Can anyone definitively quote a definitive source on
this matter? IE chapter and verse of what document from what date?
| When assigning objects to each other, the class operator= is used. For
| each base class part, the corresponding base class operator= is used for
| the assignment.
| When no user-defined operator= is provided, by default, memberwise
| assingnment is used to assign class members to each other.
In which case objects with array members cannot be assigned to each
other since assignment is illegal on arrays? I still believe this
issue needs to be cleaned up, although some claim otherwise. At the
very least, "memberwise" assignment on array members should be defined
to mean "bitwise assignment" -- although that begs the question why fixed
length arrays are not assignable?