top of page

C++ Object Slicing Simplified

  • Writer: Sunil Kumar Yadav
    Sunil Kumar Yadav
  • 20 hours ago
  • 3 min read

Object-oriented programming and polymorphism are fundamental concepts in C++. Most developers learn that virtual functions allow derived classes to provide specialized implementations while interacting through a base class interface.


However, there is a subtle issue that can silently break polymorphism: Object Slicing.

In this article, we'll understand what object slicing is, why it happens, and how to avoid it using a few simple examples.


What is Object Slicing?

Object slicing occurs when a derived class object is copied into a base class object by value.

During this copy operation, only the base class portion of the object is preserved. Any data and behavior specific to the derived class are discarded (or "sliced off").


Let's look at an example.

#include <iostream>

class Vehicle
{
public:
    virtual void Print() const
    {
        std::cout << "Vehicle" << std::endl;
    }
};

class Car : public Vehicle
{
public:
    void Print() const override
    {
        std::cout << "Car" << std::endl;
    }
};

int main()
{
    Car car;
    Vehicle vehicle = car;
    vehicle.Print();
}

Output:

Vehicle

Many developers expect the output to be:

Car

but that's not what happens. The reason is that the statement below creates a new Vehicle object:

Vehicle vehicle = car;

Only the Vehicle portion of car is copied into vehicle. As a result, the object stored in vehicle is no longer a Car. It is simply a Vehicle.


If you are using classes you must pass references to avoid object slicing. Bjarne Stroustrup, Creator of C++ 

Visualizing Object Slicing

Consider the following classes:

class Base
{
    int a;
};

class Derived : public Base
{
    int b;
};

A Derived object can be visualized as:

+---------+
| Base::a |
+---------+
| b       |
+---------+

When we write:

Base obj = derived;

the resulting object becomes:

+---------+
| Base::a |
+---------+

The member b no longer exists in the copied object. This loss of derived-class information is called object slicing.



A Common Real-World Example

Object slicing frequently occurs when objects are passed by value. Consider the following code:

#include <iostream>

class Animal {
public:
    virtual void Speak() const {
        std::cout << "Animal Sound" << std::endl;
    }
};

class Dog : public Animal {
public:
    void Speak() const override {
        std::cout << "Bark Bark" << std::endl;
    }
};

void MakeAnimalSpeak(Animal animal) {
    animal.Speak();
}

int main() {
    Dog dog;
    MakeAnimalSpeak(dog);
}

Output:

Animal Sound

At first glance, this may seem surprising. The function parameter:

Animal animal

creates a copy of the argument. Before entering the function, the Dog object is sliced into an Animal object. Consequently, the virtual dispatch mechanism only sees an Animal object and invokes:

Animal::Speak()

instead of:

Dog::Speak()

The slicing problem is serious because it can result in memory corruption, and it is very difficult to guarantee a program does not suffer from it. To design it out of the language, classes that support inheritance should be accessible by reference only (not by value). — Walter Bright, Creator of the D programming language

The Correct Approach

The most common solution is to pass objects by reference.

void MakeAnimalSpeak(const Animal& animal) {
    animal.Speak();
}

Now running the same program produces:

Bark Bark

Since no copy is created, no slicing occurs. The reference continues to refer to the original Dog object, allowing virtual dispatch to work correctly.


Object Slicing in STL Containers

Another place where developers accidentally encounter slicing is when storing polymorphic objects in containers. Consider:

std::vector<Shape> shapes;
shapes.push_back(Circle());

The Circle object is copied into a Shape object stored inside the vector. The derived portion is discarded. A better approach is:

std::vector<std::unique_ptr<Shape>> shapes;

or

std::vector<std::shared_ptr<Shape>> shapes;

This preserves polymorphic behavior and avoids slicing.


Conclusion

Object slicing occurs whenever a derived object is copied into a base object by value.

Common situations include:

  • Assigning a derived object to a base object

  • Passing polymorphic objects by value

  • Returning base objects by value

  • Storing polymorphic objects in containers by value

To avoid object slicing:

  • Prefer references (Base&)

  • Prefer pointers (Base*)

  • Use smart pointers (std::unique_ptr, std::shared_ptr) when ownership is required

  • Avoid passing polymorphic types by value

Object slicing is not a compiler error. The code compiles successfully and often appears to work correctly. This makes it one of those subtle C++ issues that every developer should understand, especially when working with inheritance and polymorphism.

Comments


©2019 by EmbeddedHow. Proudly created with Wix.com

bottom of page