Site Tools


wiki:slicing

Slicing

Object slicing happens when a derived-class object is copied into a base-class object by value: only the base subobject gets copied, and everything the derived class added is silently discarded (“sliced off”). The code compiles cleanly and runs without crashing, which is exactly what makes it a dangerous, experience-only trap rather than something a beginner learns from a compiler error.

struct Base {
    int x = 1;
    virtual void print() const { std::cout << "Base\n"; }
};
 
struct Derived : Base {
    int y = 2;
    void print() const override { std::cout << "Derived\n"; }
};
 
void byValue(Base b) { b.print(); }   // takes Base by value
 
Derived d;
byValue(d);   // prints "Base", not "Derived" — d was sliced to a Base

Why virtual dispatch doesn't save it

Virtual functions dispatch based on an object's actual dynamic type, but that only works through a pointer or reference to the object, not when the object itself has been copied into a differently-typed variable. byValue(Base b) constructs a genuine, separate Base object using Base's copy constructor; the y member and the overridden print() behavior never existed on that object in the first place, there is no dynamic type left to dispatch on. This is different from the usual “did I forget virtual” mistake: slicing happens even with a fully correct virtual function setup, because the problem is the by-value parameter, not the missing keyword.

void byRef(const Base &b) { b.print(); }   // takes Base by reference
byRef(d);   // prints "Derived" — no copy, no slicing, virtual dispatch works

Where it actually bites

Slicing shows up most often in container code and generic algorithms that quietly copy by value: pushing a Derived into a std::vector<Base> slices every element on insertion, and a function template parameter deduced or declared as Base rather than Base& slices on every call, even though nothing in the code looks wrong at a glance. The standard defense is polymorphic types should be passed and stored by reference or pointer (commonly a smart pointer like unique_ptr or shared_ptr), never by value, and a class meant to be used polymorphically should make that intent explicit by deleting or protecting its copy constructor if slicing would never be correct for it.

wiki/slicing.md · Last modified: by 127.0.0.1