By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,028 Members | 1,092 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,028 IT Pros & Developers. It's quick & easy.

Assignment through base class reference

P: n/a
What measures should be taken to avoid this sort of thing?

class Base
{
};

class Derived1 : public Base
{
private:
int i, j, k;
};

class Derived2 : public Base
{
private:
double l, m, n;
};

void BaseAssign(Base& lhs, Base& rhs)
{
lhs = rhs;
}

int main(int argc, char *argv[])
{
Derived1 d1;
Derived2 d2;

BaseAssign(d1, d2);
}

// End code snippet

The only way I can see around preventing this sort of thing is
declaring the assignment operators and copy constructors of non-leaf
classes protected, and providing clone/create methods instead of
letting the operators/constructors be used.

Do people generally just not worry about this sort of thing? I'm
absolutely paranoid about stuff like this.

Jan 20 '06 #1
Share this Question
Share on Google+
11 Replies


P: n/a
an**************@googlemail.com wrote:
What measures should be taken to avoid this sort of thing?
WHY?
class Base
{
};

class Derived1 : public Base
{
private:
int i, j, k;
};

class Derived2 : public Base
{
private:
double l, m, n;
};

void BaseAssign(Base& lhs, Base& rhs)
{
lhs = rhs;
}

int main(int argc, char *argv[])
{
Derived1 d1;
Derived2 d2;

BaseAssign(d1, d2);
}

// End code snippet

The only way I can see around preventing this sort of thing is
Why prevent this sort of thing? Do you experience any problem? Please
elaborate.
declaring the assignment operators and copy constructors of non-leaf
classes protected, and providing clone/create methods instead of
letting the operators/constructors be used.

Do people generally just not worry about this sort of thing? I'm
absolutely paranoid about stuff like this.


Well, could you share? Maybe I need to become paranoid about it as
well...

V
Jan 20 '06 #2

P: n/a

Victor Bazarov wrote:
an**************@googlemail.com wrote:
What measures should be taken to avoid this sort of thing?


WHY?
class Base
{
};

class Derived1 : public Base
{
private:
int i, j, k;
};

class Derived2 : public Base
{
private:
double l, m, n;
};

void BaseAssign(Base& lhs, Base& rhs)
{
lhs = rhs;
}

int main(int argc, char *argv[])
{
Derived1 d1;
Derived2 d2;

BaseAssign(d1, d2);
}

// End code snippet

The only way I can see around preventing this sort of thing is


Why prevent this sort of thing? Do you experience any problem? Please
elaborate.
declaring the assignment operators and copy constructors of non-leaf
classes protected, and providing clone/create methods instead of
letting the operators/constructors be used.

Do people generally just not worry about this sort of thing? I'm
absolutely paranoid about stuff like this.


Well, could you share? Maybe I need to become paranoid about it as
well...

V


The classes must be getting sliced... I mean, how can a Derived2 be
assigned to a Derived1?

Jan 20 '06 #3

P: n/a
an**************@googlemail.com wrote:
Victor Bazarov wrote:
an**************@googlemail.com wrote:
What measures should be taken to avoid this sort of thing?


WHY?

class Base
{
};

class Derived1 : public Base
{
private:
int i, j, k;
};

class Derived2 : public Base
{
private:
double l, m, n;
};

void BaseAssign(Base& lhs, Base& rhs)
{
lhs = rhs;
}

int main(int argc, char *argv[])
{
Derived1 d1;
Derived2 d2;

BaseAssign(d1, d2);
}

// End code snippet

The only way I can see around preventing this sort of thing is


Why prevent this sort of thing? Do you experience any problem? Please
elaborate.

declaring the assignment operators and copy constructors of non-leaf
classes protected, and providing clone/create methods instead of
letting the operators/constructors be used.

Do people generally just not worry about this sort of thing? I'm
absolutely paranoid about stuff like this.


Well, could you share? Maybe I need to become paranoid about it as
well...

V

The classes must be getting sliced... I mean, how can a Derived2 be
assigned to a Derived1?


Where did you get that idea, about slicing? The Base subobject of 'd1' is
simply made _the_same_ as the Base subobject of 'd2'. At least that's
what it means [to me] *semantically*. Nothing more and nothing less.

Whatever 'd1' has _above_and_beyond_ its 'Base' subobject, is kept intact.
Whatever 'd2' has _above_and_beyond_ its 'Base' subobject, is not used at
all in that operation. I suppose the following is even scarier to you:

class Derived3 : public Derived2 {};
class Derived4 : public Derived3 { std::string name; };

...
Derived4 d4;
BaseAssign(d1, d4);

It shouldn't be. Relax. Take a deep breath. Nothing *bad* is happening
here. If your problem domain prohibits that (for whatever reason, you did
not say anything about the problem domain), you _could_ disable it by
making 'Base' protected base class, but then LSP cannot be applied...
Maybe that's what you want... Speak up, then.

V
Jan 20 '06 #4

P: n/a

Victor Bazarov wrote:
an**************@googlemail.com wrote:
Victor Bazarov wrote:
an**************@googlemail.com wrote:

What measures should be taken to avoid this sort of thing?

WHY?
class Base
{
};

class Derived1 : public Base
{
private:
int i, j, k;
};

class Derived2 : public Base
{
private:
double l, m, n;
};

void BaseAssign(Base& lhs, Base& rhs)
{
lhs = rhs;
}

int main(int argc, char *argv[])
{
Derived1 d1;
Derived2 d2;

BaseAssign(d1, d2);
}

// End code snippet

The only way I can see around preventing this sort of thing is

Why prevent this sort of thing? Do you experience any problem? Please
elaborate.
declaring the assignment operators and copy constructors of non-leaf
classes protected, and providing clone/create methods instead of
letting the operators/constructors be used.

Do people generally just not worry about this sort of thing? I'm
absolutely paranoid about stuff like this.

Well, could you share? Maybe I need to become paranoid about it as
well...

V

The classes must be getting sliced... I mean, how can a Derived2 be
assigned to a Derived1?


Where did you get that idea, about slicing? The Base subobject of 'd1' is
simply made _the_same_ as the Base subobject of 'd2'. At least that's
what it means [to me] *semantically*. Nothing more and nothing less.

Whatever 'd1' has _above_and_beyond_ its 'Base' subobject, is kept intact.
Whatever 'd2' has _above_and_beyond_ its 'Base' subobject, is not used at
all in that operation. I suppose the following is even scarier to you:

class Derived3 : public Derived2 {};
class Derived4 : public Derived3 { std::string name; };

...
Derived4 d4;
BaseAssign(d1, d4);

It shouldn't be. Relax. Take a deep breath. Nothing *bad* is happening
here. If your problem domain prohibits that (for whatever reason, you did
not say anything about the problem domain), you _could_ disable it by
making 'Base' protected base class, but then LSP cannot be applied...
Maybe that's what you want... Speak up, then.

V


You seem to get angry when people ask civil questions about things they
don't understand. I feel like I'm going to be shouted at just for being
inquisitive and trying to understand something properly.

So assignment doesn't work "polymorphically"? This differs to C# (I
wrote a similar test, and found that the object of type Derived1
/becomes/ a Derived2 when assigned through a Base reference). I guess
this is why boxing works in C# with the universal base class "object".

Jan 21 '06 #5

P: n/a
an**************@googlemail.com wrote:
Victor Bazarov wrote:
an**************@googlemail.com wrote:
Victor Bazarov wrote:

an**************@googlemail.com wrote:

> What measures should be taken to avoid this sort of thing?

WHY?
> class Base
> {
> };
>
> class Derived1 : public Base
> {
> private:
> int i, j, k;
> };

> class Derived2 : public Base
> {
> private:
> double l, m, n;
> };
>
> void BaseAssign(Base& lhs, Base& rhs)
> {
> lhs = rhs;
> }
>
> int main(int argc, char *argv[])
> {
> Derived1 d1;
> Derived2 d2;
>
> BaseAssign(d1, d2);
> }
>
> // End code snippet
>
> The only way I can see around preventing this sort of thing is

Why prevent this sort of thing? Do you experience any problem?
Please elaborate.
> declaring the assignment operators and copy constructors of
> non-leaf classes protected, and providing clone/create methods
> instead of letting the operators/constructors be used.
>
> Do people generally just not worry about this sort of thing? I'm
> absolutely paranoid about stuff like this.

Well, could you share? Maybe I need to become paranoid about it as
well...

V
The classes must be getting sliced... I mean, how can a Derived2 be
assigned to a Derived1?

Where did you get that idea, about slicing? The Base subobject of
'd1' is simply made _the_same_ as the Base subobject of 'd2'. At
least that's what it means [to me] *semantically*. Nothing more and
nothing less.

Whatever 'd1' has _above_and_beyond_ its 'Base' subobject, is kept
intact. Whatever 'd2' has _above_and_beyond_ its 'Base' subobject,
is not used at all in that operation. I suppose the following is
even scarier to you:

class Derived3 : public Derived2 {};
class Derived4 : public Derived3 { std::string name; };

...
Derived4 d4;
BaseAssign(d1, d4);

It shouldn't be. Relax. Take a deep breath. Nothing *bad* is
happening here. If your problem domain prohibits that (for whatever
reason, you did not say anything about the problem domain), you
_could_ disable it by making 'Base' protected base class, but then
LSP cannot be applied... Maybe that's what you want... Speak up,
then.

V


You seem to get angry when people ask civil questions about things
they don't understand. I feel like I'm going to be shouted at just
for being inquisitive and trying to understand something properly.


Oh, please...

<shrug> Angry? I say "relax", and you think I am angry all of
a sudden? What is it, inferiority complex? Did somebody use to
shout at you for not understanding something? Never mind. I cannot
help you fight your demons. I can only help you with C++. So,
lighten up and ask your questions.
So assignment doesn't work "polymorphically"?
It might, if you declare the assignment operator 'virtual'. But your
case doesn't have that. It definitely shouldn't do it by default, and
it doesn't.
This differs to C#
Well... If you learn C++ hoping that it behaves similarly to some
other language that may have similar letters in its name, I strongly
urge you not to. C++ is complex enough, but much more logical if you
shed some preconceptions that have crept in when you were learning
<insert_other_language_here>.
(I
wrote a similar test, and found that the object of type Derived1
/becomes/ a Derived2 when assigned through a Base reference). I guess
this is why boxing works in C# with the universal base class "object".


I don't know what "boxing" is. I never heard that term used WRT C++
objects.

C++ is a _statically_ typed language. Objects in C++ cannot change
their nature because of a simple assignment of their bases. Type of
every C++ object is defined at its creation and remains the property
of the object until the object's destruction. I, for one, find it much
more logical.

Base classes are essentially members of their respective derived classes.
Assigning new values to members doesn't change the nature of objects,
does it? Only the state. Why should assigning new values to base class
subjects be any different?

V
Jan 21 '06 #6

P: n/a
Victor Bazarov wrote:
an**************@googlemail.com wrote:
Victor Bazarov wrote:
an**************@googlemail.com wrote:
Victor Bazarov wrote:

> an**************@googlemail.com wrote:
>
>> What measures should be taken to avoid this sort of thing?
>
> WHY?
>
>
>> class Base
>> {
>> };
>>
>> class Derived1 : public Base
>> {
>> private:
>> int i, j, k;
>> };

>> class Derived2 : public Base
>> {
>> private:
>> double l, m, n;
>> };
>>
>> void BaseAssign(Base& lhs, Base& rhs)
>> {
>> lhs = rhs;
>> }
>>
>> int main(int argc, char *argv[])
>> {
>> Derived1 d1;
>> Derived2 d2;
>>
>> BaseAssign(d1, d2);
>> }
>>
>> // End code snippet
>>
>> The only way I can see around preventing this sort of thing is
>
> Why prevent this sort of thing? Do you experience any problem?
> Please elaborate.
>
>
>> declaring the assignment operators and copy constructors of
>> non-leaf classes protected, and providing clone/create methods
>> instead of letting the operators/constructors be used.
>>
>> Do people generally just not worry about this sort of thing? I'm
>> absolutely paranoid about stuff like this.
>
> Well, could you share? Maybe I need to become paranoid about it as
> well...
>
> V
The classes must be getting sliced... I mean, how can a Derived2 be
assigned to a Derived1?
Where did you get that idea, about slicing? The Base subobject of
'd1' is simply made _the_same_ as the Base subobject of 'd2'. At
least that's what it means [to me] *semantically*. Nothing more and
nothing less.

Whatever 'd1' has _above_and_beyond_ its 'Base' subobject, is kept
intact. Whatever 'd2' has _above_and_beyond_ its 'Base' subobject,
is not used at all in that operation. I suppose the following is
even scarier to you:

class Derived3 : public Derived2 {};
class Derived4 : public Derived3 { std::string name; };

...
Derived4 d4;
BaseAssign(d1, d4);

It shouldn't be. Relax. Take a deep breath. Nothing *bad* is
happening here. If your problem domain prohibits that (for whatever
reason, you did not say anything about the problem domain), you
_could_ disable it by making 'Base' protected base class, but then
LSP cannot be applied... Maybe that's what you want... Speak up,
then.

V
You seem to get angry when people ask civil questions about things
they don't understand. I feel like I'm going to be shouted at just
for being inquisitive and trying to understand something properly.


Oh, please...

<shrug> Angry? I say "relax", and you think I am angry all of
a sudden? What is it, inferiority complex? Did somebody use to
shout at you for not understanding something? Never mind. I cannot
help you fight your demons. I can only help you with C++. So,
lighten up and ask your questions.


It's the way you type. You're very abrasive. I understand that you
don't mean to sound rude, but that's definitely the way you came across
here. And I don't have time to argue with you about further
inappropriate comments that you just made.
So assignment doesn't work "polymorphically"?


It might, if you declare the assignment operator 'virtual'. But your
case doesn't have that. It definitely shouldn't do it by default, and
it doesn't.


How would this work? If we were in BaseAssign and the /virtual/
assignment operator was called, how would it possibly assign from an
incompatible type? I'm sorry if I'm getting mixed up, I just need to
clear this up for my own sanity.
This differs to C#
Well... If you learn C++ hoping that it behaves similarly to some
other language that may have similar letters in its name, I strongly
urge you not to. C++ is complex enough, but much more logical if you
shed some preconceptions that have crept in when you were learning
<insert_other_language_here>.


Fortunately I am not doing this, you're jumping to conclusions a bit. I
barely know C#, but I just about managed to write the equivalent to my
C++ test program to see what the results were. I only mentioned this as
an interesting comparison and an example of another way of thinking
about the problem.
(I
wrote a similar test, and found that the object of type Derived1
/becomes/ a Derived2 when assigned through a Base reference). I guess
this is why boxing works in C# with the universal base class "object".
I don't know what "boxing" is. I never heard that term used WRT C++
objects.

C++ is a _statically_ typed language. Objects in C++ cannot change
their nature because of a simple assignment of their bases. Type of
every C++ object is defined at its creation and remains the property
of the object until the object's destruction. I, for one, find it much
more logical.


Yes. Interestingly enough, it is often said that C# is statically
typed, despite working in a different way in my test.
to
Base classes are essentially members of their respective derived classes.
Assigning new values to members doesn't change the nature of objects,
does it? Only the state. Why should assigning new values base class
subjects be any different?


This is why I wrote my test and asked these questions. Thank you.

Jan 21 '06 #7

P: n/a
an**************@googlemail.com wrote:
Victor Bazarov wrote:
an**************@googlemail.com wrote:
So assignment doesn't work "polymorphically"?


It might, if you declare the assignment operator 'virtual'. But your
case doesn't have that. It definitely shouldn't do it by default,
and it doesn't.


How would this work? If we were in BaseAssign and the /virtual/
assignment operator was called, how would it possibly assign from an
incompatible type? I'm sorry if I'm getting mixed up, I just need to
clear this up for my own sanity.


struct Base {
virtual Base& operator=(Base& b) { return *this; }
};

struct Derived : Base {
virtual Derived& operator=(Base& b) {
// do something special
return *this;
}
};

void foo(Base & b1, Base & b2) {
b1 = b2;
}

int main() {
Derived d1, d2;
foo(d1, d2); // conversion to base causes polymorphic assignment
// to be called
d1 = d2; // "normal", non-polymorphic assignment is invoked
}
Now, study that example. There is a difference between what happens
when we say 'b1 = b2', and 'd1 = d2'. In the first case, operator=
from 'Base' is used, and it's virtual, and the true types of objects
behind 'b1' and 'b2' is 'Derived', so the final overrider is called.

What it might for, I am not sure. I never had to use it in my own
work. Search the web for "virtual assignment operator" and you will
find probably enough information to understand what people use it for.

Notice, however, that the signature of the Derived::operator=(Base&)
is only slightly different from Base::operator(Base&). It is required
to have the same argument, but the return value type can be 'Derived&'.

I've thought only of one possible use. Imagine the implementation of
the virtual operator= is like this:

virtual Derived& operator= (Base &b) {
try { // now...
Derived &d = dynamic_cast<Derived&>(b);
this->Derived::operator=(d); // use the default assignment
}
catch(...) {
this->Base::operator=(b); // fall-back functionality
}
}

Now, if there will be another derived class

struct Derived2 : Base {};

and somebody does

Derived2 d22;
foo(d1, d2);

the Derived's operator= will see that the "other" object is not of
the same type and will fall back onto copying only the Base part.

Convoluted, I know. Sometimes necessary, maybe. Again, I never had
to do that in my practice.
This differs to C#


Well... If you learn C++ hoping that it behaves similarly to some
other language that may have similar letters in its name, I strongly
urge you not to. C++ is complex enough, but much more logical if you
shed some preconceptions that have crept in when you were learning
<insert_other_language_here>.


Fortunately I am not doing this, you're jumping to conclusions a bit.
I barely know C#, but I just about managed to write the equivalent to
my C++ test program to see what the results were. I only mentioned
this as an interesting comparison and an example of another way of
thinking about the problem.


Whatever. As I said, "if"...

V
Jan 21 '06 #8

P: n/a

Victor Bazarov wrote:
an**************@googlemail.com wrote:
Victor Bazarov wrote:
an**************@googlemail.com wrote:
So assignment doesn't work "polymorphically"?

It might, if you declare the assignment operator 'virtual'. But your
case doesn't have that. It definitely shouldn't do it by default,
and it doesn't.


How would this work? If we were in BaseAssign and the /virtual/
assignment operator was called, how would it possibly assign from an
incompatible type? I'm sorry if I'm getting mixed up, I just need to
clear this up for my own sanity.


struct Base {
virtual Base& operator=(Base& b) { return *this; }
};

struct Derived : Base {
virtual Derived& operator=(Base& b) {
// do something special
return *this;
}
};

void foo(Base & b1, Base & b2) {
b1 = b2;
}

int main() {
Derived d1, d2;
foo(d1, d2); // conversion to base causes polymorphic assignment
// to be called
d1 = d2; // "normal", non-polymorphic assignment is invoked
}
Now, study that example. There is a difference between what happens
when we say 'b1 = b2', and 'd1 = d2'. In the first case, operator=
from 'Base' is used, and it's virtual, and the true types of objects
behind 'b1' and 'b2' is 'Derived', so the final overrider is called.

What it might for, I am not sure. I never had to use it in my own
work. Search the web for "virtual assignment operator" and you will
find probably enough information to understand what people use it for.

Notice, however, that the signature of the Derived::operator=(Base&)
is only slightly different from Base::operator(Base&). It is required
to have the same argument, but the return value type can be 'Derived&'.

I've thought only of one possible use. Imagine the implementation of
the virtual operator= is like this:

virtual Derived& operator= (Base &b) {
try { // now...
Derived &d = dynamic_cast<Derived&>(b);
this->Derived::operator=(d); // use the default assignment
}
catch(...) {
this->Base::operator=(b); // fall-back functionality
}
}

Now, if there will be another derived class

struct Derived2 : Base {};

and somebody does

Derived2 d22;
foo(d1, d2);

the Derived's operator= will see that the "other" object is not of
the same type and will fall back onto copying only the Base part.

Convoluted, I know. Sometimes necessary, maybe. Again, I never had
to do that in my practice.


Thanks. I had figured out virtual assignment operators in general, I
just didn't know how it would work with different types of the same
base through the base pointer. I see now that in cases like this it
only assigns the base class portion. Thanks.

Jan 21 '06 #9

P: n/a

Victor Bazarov wrote:
an**************@googlemail.com wrote:
Victor Bazarov wrote:
an**************@googlemail.com wrote:

What measures should be taken to avoid this sort of thing?

WHY?
class Base
{
};

class Derived1 : public Base
{
private:
int i, j, k;
};

class Derived2 : public Base
{
private:
double l, m, n;
};

void BaseAssign(Base& lhs, Base& rhs)
{
lhs = rhs;
}

int main(int argc, char *argv[])
{
Derived1 d1;
Derived2 d2;

BaseAssign(d1, d2);
}

// End code snippet

The only way I can see around preventing this sort of thing is

Why prevent this sort of thing? Do you experience any problem? Please
elaborate.
declaring the assignment operators and copy constructors of non-leaf
classes protected, and providing clone/create methods instead of
letting the operators/constructors be used.

Do people generally just not worry about this sort of thing? I'm
absolutely paranoid about stuff like this.

Well, could you share? Maybe I need to become paranoid about it as
well...

V

The classes must be getting sliced... I mean, how can a Derived2 be
assigned to a Derived1?


Where did you get that idea, about slicing? The Base subobject of 'd1' is
simply made _the_same_ as the Base subobject of 'd2'. At least that's
what it means [to me] *semantically*. Nothing more and nothing less.


Where do you get the idea that it isn't sliced?

I have managed to find this page, which explains in a way clearer than
I could:

http://icu.sourceforge.net/docs/pape...revisited.html

Scroll down to "virtual assignment". The author approaches the problem
first virtual assignment operators and dynamic casts (so that
incompatible assignments throw, rather than slice), and then later
improves it with an assert .

I wouldn't like to do this for every non-trivial class - would you? I
tend to design around this sort of thing where possible.

Jan 22 '06 #10

P: n/a
an**************@googlemail.com wrote:
Victor Bazarov wrote:
an**************@googlemail.com wrote:
Victor Bazarov wrote:

an**************@googlemail.com wrote:

> What measures should be taken to avoid this sort of thing?

WHY?
> class Base
> {
> };
>
> class Derived1 : public Base
> {
> private:
> int i, j, k;
> };
>
> class Derived2 : public Base
> {
> private:
> double l, m, n;
> };
>
> void BaseAssign(Base& lhs, Base& rhs)
> {
> lhs = rhs;
> }
>
> int main(int argc, char *argv[])
> {
> Derived1 d1;
> Derived2 d2;
>
> BaseAssign(d1, d2);
> }
>
> // End code snippet
>
> The only way I can see around preventing this sort of thing is

Why prevent this sort of thing? Do you experience any problem?
Please elaborate.
> declaring the assignment operators and copy constructors of
> non-leaf classes protected, and providing clone/create methods
> instead of letting the operators/constructors be used.
>
> Do people generally just not worry about this sort of thing? I'm
> absolutely paranoid about stuff like this.

Well, could you share? Maybe I need to become paranoid about it as
well...

V
The classes must be getting sliced... I mean, how can a Derived2 be
assigned to a Derived1?

Where did you get that idea, about slicing? The Base subobject of
'd1' is simply made _the_same_ as the Base subobject of 'd2'. At
least that's what it means [to me] *semantically*. Nothing more and
nothing less.


Where do you get the idea that it isn't sliced?


Slicing happens if you _construct_ a base class object from a derived
class object. In your case no construction happens. Assignment in its
pure form is _giving_new_values_ to pre-existing objects. There is no
room for slicing there. Period. I guess some have been misusing the
term "slicing".
I have managed to find this page, which explains in a way clearer than
I could:

http://icu.sourceforge.net/docs/pape...revisited.html

Scroll down to "virtual assignment". The author approaches the problem
first virtual assignment operators and dynamic casts (so that
incompatible assignments throw, rather than slice), and then later
improves it with an assert .

I wouldn't like to do this for every non-trivial class - would you? I
tend to design around this sort of thing where possible.


How is what the author is writing relevant to your case? I am just
wondering.

Besides, even considering that his fragment

X* x;
void setX(const X& newX) {
x = newX;
}

_is_ part of a class (who in their right mind is going to keep global
pointers and set them using some function?), then it still has nothing
to do with slicing because it's not the _object_ that's assigned, it's
the pointer.

As I already said in another reply, I've not encountered the need to
define a virtual assignment operator in my entire C++ career. That is
not necessarily an argument against them, it's just an indication that
the need in them is rare.

V
Jan 22 '06 #11

P: n/a
Victor Bazarov wrote:
an**************@googlemail.com wrote:
Victor Bazarov wrote:
an**************@googlemail.com wrote:
Victor Bazarov wrote:

> an**************@googlemail.com wrote:
>
>> What measures should be taken to avoid this sort of thing?
>
> WHY?
>
>
>> class Base
>> {
>> };
>>
>> class Derived1 : public Base
>> {
>> private:
>> int i, j, k;
>> };
>>
>> class Derived2 : public Base
>> {
>> private:
>> double l, m, n;
>> };
>>
>> void BaseAssign(Base& lhs, Base& rhs)
>> {
>> lhs = rhs;
>> }
>>
>> int main(int argc, char *argv[])
>> {
>> Derived1 d1;
>> Derived2 d2;
>>
>> BaseAssign(d1, d2);
>> }
>>
>> // End code snippet
>>
>> The only way I can see around preventing this sort of thing is
>
> Why prevent this sort of thing? Do you experience any problem?
> Please elaborate.
>
>
>> declaring the assignment operators and copy constructors of
>> non-leaf classes protected, and providing clone/create methods
>> instead of letting the operators/constructors be used.
>>
>> Do people generally just not worry about this sort of thing? I'm
>> absolutely paranoid about stuff like this.
>
> Well, could you share? Maybe I need to become paranoid about it as
> well...
>
> V
The classes must be getting sliced... I mean, how can a Derived2 be
assigned to a Derived1?
Where did you get that idea, about slicing? The Base subobject of
'd1' is simply made _the_same_ as the Base subobject of 'd2'. At
least that's what it means [to me] *semantically*. Nothing more and
nothing less.
Where do you get the idea that it isn't sliced?


Slicing happens if you _construct_ a base class object from a derived
class object. In your case no construction happens. Assignment in its
pure form is _giving_new_values_ to pre-existing objects. There is no
room for slicing there. Period. I guess some have been misusing the
term "slicing".


It might not be a perfect term for what's going on (you could say
"sliced assignment" instead), but that doesn't make the problem
(however contrived it might be) any less real. I certainly feel better
for investigating it.
I have managed to find this page, which explains in a way clearer than
I could:

http://icu.sourceforge.net/docs/pape...revisited.html

Scroll down to "virtual assignment". The author approaches the problem
first virtual assignment operators and dynamic casts (so that
incompatible assignments throw, rather than slice), and then later
improves it with an assert .

I wouldn't like to do this for every non-trivial class - would you? I
tend to design around this sort of thing where possible.
How is what the author is writing relevant to your case? I am just
wondering.


Looking at it now, his code sample seems wrong. I think this:

X* x;

void setX(const X& newX) {
x = &newX;
}

should actually be this:

X x;

void setX(const X& newX) {
x = newX;
}

to match his text (perhaps he DOESN'T explain it better than I could
after all!). But you see how THAT relates to my problem and the
solutions written after it, don't you?

Besides, even considering that his fragment

X* x;
void setX(const X& newX) {
x = newX;
}

_is_ part of a class (who in their right mind is going to keep global
pointers and set them using some function?), then it still has nothing
to do with slicing because it's not the _object_ that's assigned, it's
the pointer.

As I already said in another reply, I've not encountered the need to
define a virtual assignment operator in my entire C++ career. That is
not necessarily an argument against them, it's just an indication that
the need in them is rare.


The problem is very contrived and artificial. I just wanted to
investigate as part of the process of understanding the language as
much as possible.

Interestingly, the guy in that article seems to have received a lot of
e-mails from people (including his own boss) who think otherwise, which
prompted him to write about the problem. Obviously some people /do/
have issues with polymorphic assignment in this way. I can see both
sides, really - objects might end up in an invalid state of only the
Base part of them gets assigned, whilst on the other hand - when is
this ever going to happen, and is it simply a side effect of
over-complex design?

Thanks for your input, Victor.

Jan 22 '06 #12

This discussion thread is closed

Replies have been disabled for this discussion.