Object slicing is an effect that takes place when a derived object is initialized or copied to base class object. For example:

#include <iostream>
 
class Base
{
    int m_base_value{10};
 
public:
    Base(int value)
        : m_base_value{value}
    {
    }
    
    virtual void callme()
    {
        std::cout << "Base object with base value: " << getValue() << '\n';
    }
 
    int getValue() const
    {
        return m_base_value;
    }
};
 
class Derived : public Base
{
public:
    Derived(int value)
        : Base{value}
    {
    }
 
    void callme()
    {
        std::cout << "Derived object with base value: " << getValue() << '\n';
    }
};
 
int main(int argc, char const *argv[])
{
    Derived d{100};
    
    Base b{d};
    b.callme();
    
    Base *b_ptr{&d};
    b_ptr->callme();
    return 0;
}

Here, we created Derived object d and then initialized it to the object of type Base. When we do this, only the Base portion of the derived object is received to the Base type object. When we call callme function the Base type object, it calls the Base version of the function even though the function was virtual. On the other hand, when we use Base pointer, the derived version of the callme function gets used.

If we do not want this behavior,, we can delete the copy constructor and copy assignment operator as follows:

class Base
{
    int m_base_value{10};
 
public:
    Base(int value)
        : m_base_value{value}
    {
    }
 
    // to prevent object slicing
    Base(const Base &b) = delete;
    Base &operator=(const Base &b) = delete;
 
    virtual void callme()
    {
        std::cout << "Base object with base value: " << getValue() << '\n';
    }
 
    int getValue() const
    {
        return m_base_value;
    }
};

Deleting these functions, we solve two problems:

  1. Prevent passing object by value to function where object slicing can happen and may cause bugs in the code.
  2. Prevent creation of frakenobject.

Slicing with functions

Most of the time, object slicing occurs when we accidentally pass object by value to a function with parameter of base class type.

void doSomething(Base obj)
{
    obj.callme();
}
 
Derived d{100};
doSomething(d);

We might be expecting it call derived version of callme but to surprise, it calls base version because the object slicing has happened while passing d to the function by value.

While this is very simple case here to find out the issue, however, in big programs, it becomes very hard to figure out the issue.

Frakenobject

Now consider the following program:

Derived d{100};
Derived d2{300};
 
Base& ref{d};
 
ref = d2;

Here, we are assigning d2 to the reference of d. This will only copy the base portion from d2 object to object d while remaining derived portion. However, this may not be what is expected.

So, by deleting copy constructor and assignment operator of the base class, we can avoid these two problems.

References

  1. https://www.learncpp.com/cpp-tutorial/object-slicing/