0

I have the following MWE code:

#include <algorithm>

class Base{
public:
    int baseMember;
    friend void swap(Base& in, Base& out)
    {
        using std::swap;
        swap(in.baseMember, out.baseMember);
    }
    virtual Base& operator=(Base obj)
    {
        swap(*this, obj);
        return *this;
    }
    Base() : baseMember(1)
    {       
    }
};
class Derived : public Base
{
public:
    int derivedMember;
    friend void swap(Derived& in, Derived& out)
    {
        using std::swap;
        swap(in.derivedMember, out.derivedMember);
        swap(static_cast<Base&>(in), static_cast<Base&>(out));
    }
    virtual Base& operator=(Base obj)
    {
        swap(*this, static_cast<Derived&>(obj));
        return *this;
    }
    Derived() : Base(), derivedMember(2)
    {
    }
};

int main()
{
    Base *b1 = new Derived();
    Base *b2 = new Derived();
    *b1 = *b2;
    delete b1;
    delete b2;
}

I have two Base pointers pointing to Derived data. I then do an assignment of the contents of the pointers. Since the Base class' assignment operator is virtual, polymorphism kicks in and the assignment operator of the Derived class (with the same signature) is called instead.

However, the static_cast to transform the source into a Derived object fails. Or, well, it successfully transforms it into a Derived object, but its derivedMember is garbage (after being initially set in the constructor).

How can this be avoided? How can an assignment between the Derived contents of two Base pointers be done?

Wasabi
  • 2,879
  • 3
  • 26
  • 48
  • Use `dynamic_cast` instead, it's safer because it checks if reference is *really* refers to `Derived` object. – PcAF Jun 01 '16 at 19:30

2 Answers2

3

Your code has a typo and inherently unsafe behavior. The typo is here:

virtual Base& operator=(Base obj) // <-- should be base&
{
    swap(*this, static_cast<Derived&>(obj));
    return *this;
}

If you fix this, your code should work in the simple example provided. But it would still fail at large, because how would you guarantee the argument passed to operator= will be in fact of Derived type?

SergeyA
  • 61,605
  • 5
  • 78
  • 137
1

Passing an argument by value slices that argument. So by the time your operator= function is called, you have an actual Base, not a Derived.

I'm afraid you'll need to overload your assignment for lvalues and rvalues.

virtual Base& operator=(const Base&);
virtual Base& operator=(Base&&);
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • Ah. Of course. I was trying to use the copy-swap idiom and make use of the copy-constructor, but of course that'll only create a copy of `Base`. However, does this mean copy-swap doesn't work in such a case? I can't use `swap()` on a constant reference or on an rvalue. – Wasabi Jun 01 '16 at 20:11
  • Or should I use the const reference to create a temporary object and use that in the `swap`, as what the [SO C++ FAQ on copy-swap](http://stackoverflow.com/a/3279550/2175231) calls a "naive implementation of the idiom"? – Wasabi Jun 01 '16 at 20:24