Assignment Operator Inheritance

Assignment operator inheritance

You don't have a default

Derived& operator=(const Base& a);

in your Derived class.

A default assignment operator, however, is created:

Derived& operator=(const Derived& a);

and this calls the assignment operator from Base. So it's not a matter of inheriting the assignment operator, but calling it via the default generated operator in your derived class.

Is the assignment operator inherited or not?

The generated assignment is "all the base assignments, in order of inheritance declaration", so your generated assignment is essentially

D& operator=(const D& d)
{
B::operator=(d);
return *this;
}

If you were to derive from both B and C - in that order; class D: B, C - it would be equivalent to

D& operator=(const D& d)
{
B::operator=(d);
C::operator=(d);
return *this;
}

That is, the assignment is not inherited, but it's used.

C++ assignment operator implementation on derived class

Like this:

Derived &operator=(const Derived &right )
{
if (&right == this) { return *this; } // prevent assigning to self
Base::operator=(right);
delete derivedMember; // remember to release any assigned memory (assumes derivedMember is assigned a default of nullPtr)
derivedMember = new double( *(right.derivedMember) );
return *this;
}

Calling copy and assignment operators from base class to create inherited class instances in C++

Yes, you would have to define something like that.

B(const A& other);

This would allow constructing B out of A. This would also allow assigning A to B by way of implicitly converting A to B and then assigning. So that alone should suffice. But you get an extra copy.

B& operator=(const A& other);

This makes assigning A to B more efficient since you avoid the extra copy of the temporary B. This should also allow assigning things that can be implicitly converted to A like:

B b = 1;

If you don't want that you might have to add some explicit. Did C++98 have explicit? That is so last millenium.

Note: In modern C++ this would be more efficient because of copy elision and because you could use move semantic and perfect forwarding references.

Assignment operator not available in derived class

Every class has at least one assignment operator implicitly defined when we don't provide one ourselves.

And when a member function in a derived class is defined with the same name as a member in the base class, it hides all the base class definitions for that name.

You can use a using declaration, but be warned that it will pull all the members named operator= and allow code like this:

A a;
B b;
b = a;

Which is slightly dubious.

Move assignment operator and virtual inheritance

The problem is that FT's FT& operator= (FT&&) = default; is essentially:

FT& operator=(FT&& other) {
// Move-assign base classes
static_cast<UG&>(*this) = std::move(static_cast<UG&>(other)); // Also move-assigns G
// other.mem_G is now empty after being moved
static_cast<T&>(*this) = std::move(static_cast<T&>(other)); // Also move-assigns G
// this->mem_G is now empty
// Move-assign members
mem_FT = std::move(other.mem_FT);
}

(Though not exactly. A compiler is allowed to be smart and only move from a virtual base class once, but that doesn't happen with gcc and clang at least)

Where the single base class subobject G is moved into from other twice (through the two move assigns). But other.mem_G is empty after the first move, so it will be empty after the move assign.

The way to deal with this is to make sure that the virtual base is only move-assigned once. This can easily be done by writing something like this:

FT& operator=(FT&& other) noexcept {
// Also move-assigns `G`
static_cast<T&>(*this) = std::move(static_cast<T&>(other));
// Move-assign UG members without UG's move assign that moves `G`
mem_UG = std::move(other.mem_UG);
// Move-assign FT members
mem_FT = std::move(other.mem_FT);
}

With private members or a more complicated move-assign, you might want to make a protected move_only_my_members_from_this_type_and_not_virtual_bases(UG&&) member function

You can also fix this by not generating a default move-assign operator, making the base class be copied twice instead of becoming empty, for a potential performance hit.



Related Topics



Leave a reply



Submit