Copy constructors and copy assignement operators in inheritance

Let us see how copy and move constructors and overloaded operator= work with inheritance. The first thing to remember is that copy and move constructors and copy and move assignment operators are not automatically inherited from the base class.

Sometimes, compiler provided versions are fine, but sometimes, we need to provide our version of these operations. If a base class a copy constructor, we can invoke base copy and move operations explicitly from the derived class. In that case, the compiler will do so-called “slicing” to slice out the base part from the derived

Here is a simple example of copy constructors in inheritance.

class Base
{
private:
  int x;
public:
  Base(Base const& other) : x{other.x} {} // copy constructor of base
};

class Derived : public Base
{
private:
  int y;
public:
  Derived(Derived const& other) : Base{other}, y{other.y} {} // copy constructor of Dervide that will call copy constructor of Base --> slicing
};

In this code, Derived publicly inherits from Base. In this example, the Base class constructor expects a reference to the Base object, but here we have a Derived object in the derived class which is in our case referred to as “other”. What we want to do is to explicitly invoke the Base class constructor.

Because we have a public inheritance, which means that Derived IS-A Base, we can pass the “other” as a parameter to Base. That is the point, where the compiler uses “slicing”, and slices out the base part of the Derived object. Once we copy the sliced part, the int y part will be copied and code inside the curly will be run. The move constructor works the same way.

Here is a simple example of a copy assignment operator.

class Base
{
private:
  int x;
public:
  //..
  Base& operator=(Base const& other) // copy assignement operator=
  {
    if (this == &other)
    {	
      return *this;
    } 
    else 
    {
      x = other.x;
      return *this;
    }
  }
};

class Derived : public Base
{
private:
  int y;
public:
  Derived& operator=(Derived const& other) // copy assignement operator
  {
    if (this == &other)
    {
      return *this;
    }
    else
    {
      Base::operator=(other); // assign the Base part of Derived --> slicing
      y = other.y;
      return *this;
    }
  }
};

If there is no need to provide a copy or move constructor and copy or move operator=, do not provide them.

If we do not define them in the derived class, the compiler will provide them automatically and call the base’s version. If we do provide them in derived, then we must explicitly call the base’ s version.

The bottom line. 

If a class has a raw pointer, we need to provide them and we need to use deep copy semantics.