Unexpected result with virtual operator= overload


L

Lloyd

Hi,

This is a small code piece I have written to test. It is overloading "operator=". To my surprise this code prints "base" always! If I overload "operator+" it prints "derived". Can you give a reason why "=" behaves that way in this code?

#include <iostream>
using std::cout;

class derived;

class base
{
public:
virtual derived& operator=(const base& rhs);
};

class derived: public base
{
public:
derived& operator=(const base& rhs);
};

derived x;
derived& base::eek:perator=(const base& rhs)
{
cout<<"base\n";
return x;
}

derived& derived::eek:perator=(const base& rhs)
{
cout<<"derived\n";
return x;
}

int main()
{
derived d,e;
d=e;
return 0;
}

Thanks,
Lloyd
 
Ad

Advertisements

T

Tobias Müller

Lloyd said:
Hi,

This is a small code piece I have written to test. It is overloading
"operator=". To my surprise this code prints "base" always! If I overload
"operator+" it prints "derived". Can you give a reason why "=" behaves
that way in this code?

#include <iostream>
using std::cout;

class derived;

class base
{
public:
virtual derived& operator=(const base& rhs);

This is a copy assignment operator for base.
The return type is unusual but it's a copy assignment operator
nevertheless.
};

class derived: public base
{
public:
derived& operator=(const base& rhs);

This is _not_ a copy assignment operator for derived, the parameter type
does not match.

This means that derived has a compiler-generated copy constructor, which
calls the copy assignment operator for all base classes and members.
};

derived x;
derived& base::eek:perator=(const base& rhs)
{
cout<<"base\n";
return x;
}

derived& derived::eek:perator=(const base& rhs)
{
cout<<"derived\n";
return x;
}

int main()
{
derived d,e;
d=e;

Copy assignment operator for derived is called, not your custom assignment
operator.
return 0;
}

Such unconventional operator overloading only confuses people, including
yourself. At least the return type should always be the type where the
operator is declared. And always "return *this;", not some unrelated
object.

Tobi
 
T

Tobias Müller

Tobias Müller said:
This is a copy assignment operator for base.
The return type is unusual but it's a copy assignment operator
nevertheless.


This is _not_ a copy assignment operator for derived, the parameter type
does not match.

This means that derived has a compiler-generated copy constructor, which

Compiler-generated copy assignment operator of course, sorry
 
L

Lloyd

This is a copy assignment operator for base.

The return type is unusual but it's a copy assignment operator

nevertheless.






This is _not_ a copy assignment operator for derived, the parameter type

does not match.



This means that derived has a compiler-generated copy constructor, which

calls the copy assignment operator for all base classes and members.








Copy assignment operator for derived is called, not your custom assignment

operator.

Did you mean copy assignment operator for *base* is called?

Such unconventional operator overloading only confuses people, including

yourself. At least the return type should always be the type where the

operator is declared. And always "return *this;", not some unrelated

object.



Tobi


May I know the reason why it prints "derived" when changing the operator from "=" to "+"?. Does operator associativity has some role to play here? Thanks for your detailed explanation

Lloyd
 
V

Victor Bazarov

Did you mean copy assignment operator for *base* is called?

No. If you declare/define your own *correct* copy assignment op in
'derived', you are going to see it used. The implicitly declared (and
implicitly defined) one in this case behaves as it should - it simply
calls the base copy assignment op that *you* defined.
May I know the reason why it prints "derived" when changing the operator from "=" to "+"?. Does operator associativity has some role to play here? Thanks for your detailed explanation

No. These operators do differ in this important aspect: there is no
implicitly defined operator+, but there *is* an implicitly defined copy
assignment op (which you didn't see called in your original example).

V
 
L

Lloyd

No. If you declare/define your own *correct* copy assignment op in

'derived', you are going to see it used. The implicitly declared (and

implicitly defined) one in this case behaves as it should - it simply

calls the base copy assignment op that *you* defined.






No. These operators do differ in this important aspect: there is no

implicitly defined operator+, but there *is* an implicitly defined copy

assignment op (which you didn't see called in your original example).



V

Thank you very much. Now I clearly understood.


 
Ad

Advertisements

O

osmium

:

<google munged>
No. If you declare/define your own *correct* copy assignment op in

'derived', you are going to see it used. The implicitly declared (and

implicitly defined) one in this case behaves as it should - it simply

calls the base copy assignment op that *you* defined.






No. These operators do differ in this important aspect: there is no

implicitly defined operator+, but there *is* an implicitly defined copy

assignment op (which you didn't see called in your original example).



V

Thank you very much. Now I clearly understood.
<end google>

Thanks to google and their utter contempt for standards, that post is almost
entirely white space.

There must be a science fiction story that describes this situation very
well? Kind of a spin-off of Tower of Babel.
 
Ö

Öö Tiib

This is a copy assignment operator for base.
The return type is unusual but it's a copy assignment operator
nevertheless.

Another thing that is unusual is that it is virtual. I have usually
reviewed such things as defects, since I can't imagine how that virtual
assignment should work.

This is _not_ a copy assignment operator for derived, the parameter type
does not match.

Is not it also override of the virtual copy assignment operator of base class?
This means that derived has a compiler-generated copy constructor, which
calls the copy assignment operator for all base classes and members.

Interesting, why the override copy assignment operator is not called?
 
V

Victor Bazarov

Another thing that is unusual is that it is virtual. I have usually
reviewed such things as defects, since I can't imagine how that virtual
assignment should work.

If you actually assign to a derived object using a reference to base,
the *derived* assignment operator is called. Some could find it useful.
I know of no case that calls for it, but see no particular reason to
prohibit it.
Is not it also override of the virtual copy assignment operator of base class?

That's the intention, I believe.
Interesting, why the override copy assignment operator is not called?

The implicitly defined copy assignment op calls base classes' (and
members') assignment operators as if with the scope resolution, I think.
And when base:: is used, it circumvents the polymorphic call. That's
my take on it, anyway.

V
 
Ö

Öö Tiib

If you actually assign to a derived object using a reference to base,
the *derived* assignment operator is called. Some could find it useful.
I know of no case that calls for it, but see no particular reason to
prohibit it.

On all cases when I have seen "virtual operator=" it was either seeking
ways to assign apples to oranges (slicing defect) or using "operator="
for something else but copy-assignment (confusing). I would like to see
any better case.

When we need polymorphism (for example to implement a casket of fruits)
in C++ then we use base (fruit) pointers. How else? Now when we need to exchange polymorphic objects (arrange the apples and oranges around in
such casket) then most efficient seems to be to modify the values of
such pointers instead of values of the objects. Idiomatically the
polymorphic objects should be clone-able instead of being copyable.
The implicitly defined copy assignment op calls base classes' (and
members') assignment operators as if with the scope resolution, I think.
And when base:: is used, it circumvents the polymorphic call. That's
my take on it, anyway.

Yes, that makes sense. Thanks, I had not even thought of that.
 
Ad

Advertisements

V

Victor Bazarov

[..]
Another thing that is unusual is that it is virtual. I have usually
reviewed such things as defects, since I can't imagine how that virtual
assignment should work.

If you actually assign to a derived object using a reference to base,
the *derived* assignment operator is called. Some could find it useful.
I know of no case that calls for it, but see no particular reason to
prohibit it.

On all cases when I have seen "virtual operator=" it was either seeking
ways to assign apples to oranges (slicing defect) or using "operator="
for something else but copy-assignment (confusing). I would like to see
any better case.

Perhaps we get lucky and in our lifetime we come across some piece of
code that does something useful with a virtual copy assignment op. I
haven't seen one such example either. Still, not a valid reason to
prohibit it.
When we need polymorphism (for example to implement a casket of fruits)
in C++ then we use base (fruit) pointers. How else? Now when we need to exchange polymorphic objects (arrange the apples and oranges around in
such casket) then most efficient seems to be to modify the values of
such pointers instead of values of the objects. Idiomatically the
polymorphic objects should be clone-able instead of being copyable.

That concerns collections of heterogeneous objects. What if the
collection is not the context of such an assignment, but instead it is
hidden deep in some library code and a reference is used to avoid
slicing and the caller of the library wants to register the fact that
the derived object was being assigned to? Just one possible scenario.

V
 
Ad

Advertisements


Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top