Hooch
Hooch

Reputation: 29683

C++ Should I overwrite copy constructor in derived class

I have base class with custom copy constructor that takes care of alocated memory. I also have class dervied from that base. That derived class is not doing anything more with memory.

How should copy constructor look in dervied class? How about overwriting swap, move and assign?

Upvotes: 1

Views: 1466

Answers (3)

dyp
dyp

Reputation: 39141

There's the so-called rule-of-five (formerly rule-of-three), which says if you have user-defined any of those:

  • copy constructor
  • move constructor
  • destructor
  • copy assignment-operator
  • move assignment-operator

than you'll probably also want to user-define the other four.


On the other hand, there's the rule-of-zero: Instead of defining those five special member functions, you can use resource objects (RAII) that automatically take care of these things.

Whether such an object is a data member or a base class (subobject) of some class C doesn't care: The implicitly declared & defined special member functions of C provided by the compiler will invoke the special member function of this resource object, which will most probably be sufficient.

hint: A more precise answer could be given for a specific example

Upvotes: 1

Steve Jessop
Steve Jessop

Reputation: 279325

You shouldn't have to do anything other than maybe for swap. A base class is like a data member in this respect, the compiler-generated copy constructor and assignment (and moves if applicable) include it.

swap is different because there's no compiler-generated swap, just the default implementation in namespace std and then whatever specialization or ADL-overload the programmer defines for a user-defined type.

So if there's already a function that looks like:

namespace foo {
    void swap(Base &lhs, Base &rhs) {
        lhs.swap(rhs); // or maybe the gory details are in this function
    }
}

and you do nothing, and some user calls it like:

foo::swap(derived1, derived2);

then the base parts will be swapped and the derived parts won't, which is pretty bad.

Users shouldn't call swap like that, but you know what users are like. It might look especially tempting to the user if Base and Derived are in the same namespace, and they just assume it'll all work. So you might want to ensure that there's an overload for Derived in order to stop them, if you think your users are (or your own code base is) unprincipled in how it calls swap.

Users should call swap like:

using std::swap;
swap(base1, base2);
swap(derived1, derived2);

That will call foo::swap when used with Base and std::swap when called with Derived. std::swap<Derived> might be inefficient (if Base has a swap implemented for efficiency, then Derived should too). So you probably want to implement a swap for Derived for that reason too, but slow isn't as bad as wrong.

That said, you're asking about moves. If Derived is efficiently movable then std::swap<Derived> isn't bad. Maybe it can be improved on, maybe not, but it should be marginal because three moves is hard to beat.

You and users should also be aware that swap does not play nicely with polymorphism (because in general two objects must have the same complete type in order for swapping them to make sense), and implementing it for a base class might cause trouble.

Derived d1, d2;
Base &b1 = &d1, &b2 = d2;
swap(b1, d2); // swaps just the base part
swap(b1, b2); // swaps just the base part

So firstly, users need to know not to call swap like that. Secondly, you might want to consider whether or not a Base with a swap is really well-designed as a base class.

Upvotes: 3

n. m. could be an AI
n. m. could be an AI

Reputation: 120031

You cannot "overwrite" a constructor. It's not a term in the C++ vocabulary. You can override a function, but only if it's virtual.

Normally you shouldn't do anything special in the constructors of children of any correctly written base class. Let each generation take care of itself.

Upvotes: 0

Related Questions