If the actual object was of a type derived from Foo, the above
has invalidated all of the pointers to it. I'm also not too
sure, but I think destructing the base class other than from the
destructor of the derived class is undefined behavior---it
should be, anyway.
Assignment operator should as a rule never be virtual, because
that moves error detection from compile time to run time, and
also, it's easy to forget to override it, as it seems you have
forgotten in the class below?
In other words, it creates a mess.
Not to forget that there's no way to implement the actual
semantics of assignment in a derived class. Consider:
struct Base { virtual ~Base() {}; }
class D1 : public Base { /*...*/ };
class D2 : public Base { /*...*/ };
Base p = new D1;
*p = D2() ;
What should the last line mean? How do you implement it.
If you need assignment in a polymorphic class, you can fake it
using something like the letter/envelop idiom, but the cost is
usually fairly high, and it's rarely appropriate.
The other problem is, as Pete noted above, that you're
stomping all over the vtable. It's just completely
unnecessary. What is the purpose that you /think/ you're
achieving (please forgive me for not reading up the whole
thread)?
Of course, given his implementation of Foo:
perator=, there is
no more Bar object here, and any use of the this pointer after
this line is undefined behavior.
But as a general rule, the compiler generated assignment
operator is generally sufficient, and where it isn't, the fix
is most probably to equip member variables with proper copying
semantics instead of specializing the assignment operator and
other things to deal with their lack of proper copyability.
Well, you've got to start somewhere. But generally, in my
experience, a lot of classes shouldn't support assignment to
begin with. Which avoids a lot of the questioning as well.
For example, a raw pointer member variable might seem to
require some custom assignment operator in the containing
class. Solution: use a smart pointer. Not a solution:
implementing a custom assignment operator.
If the requirement is deep copy of some more or less complex
structure (e.g. like std::map), then you have to implement it.
The compiler will only do a shallow copy, and smart pointers
will only go so far.
For those few remaining cases where it's most practical to do
the custom assignment operator, you'll often find that that
the swap idiom for assignment serves your needs. This is a way
to express assignment in terms of copy construction, and it's
generally exception and self-copy safe. It goes like
T& operator=( T const& other )
{
T const copy( other ); // Using copy constructor to copy.
this->swap( copy ); // Can't throw, by design.
}
I wrote "this->" just to make it clear since it's a snippet
out of context; writing "this->" is not something that one
should do in real code...
More generally, you fully construct all necessary data, and do
anything else which might throw, before modifying the original
object. (The swap idiom is a convenient way of accomplishing
this in many cases, but for the very simplest cases, like a
pimpl using deep copy, it may be overkill, and be just as simple
to implement using the idiom which was standard before the swap
idiom was invented.)