Loading lessons...
Object Slicing and Dynamic Cast
Object Slicing and Dynamic Cast
Two tools make inheritance safe in practice: avoiding object slicing and using dynamic_cast for safe downcasting.
Object slicing: the silent bug
If you pass a derived object by value to a function that takes the base by value, only the base part gets copied. The derived members silently disappear. That is slicing.
class Animal {
public:
int legs;
};
class Dog : public Animal {
public:
string bark;
};
void print(Animal a) { } // takes the base by value
Dog rex;
print(rex); // rex's bark member is sliced off
The function receives an object that only has the Animal members. Information is silently lost.
The fix: pass by reference
Avoid the problem by passing a reference or pointer to the base:
void print(const Animal& a) { } // no copy, no slicing
References do not copy, so the derived object stays whole.
dynamic_cast: safe downcasting
Downcasting converts a base pointer back into a derived pointer. It is unsafe if the object is not actually that type. dynamic_cast checks at runtime and returns nullptr on failure:
Dog* d = dynamic_cast<Dog*>(animalPtr);
if (d) {
d->bark(); // safe: animalPtr really pointed at a Dog
} else {
cout << "Not a Dog";
}
When the pointer is not a Dog, d is nullptr, so the if statement catches the failure cleanly.
What dynamic_cast needs
The class must be polymorphic: it needs at least one virtual function (like a virtual destructor). Without that, dynamic_cast won't compile.
TL;DR
- Slicing: a base by-value copy drops the derived part.
- Use references or pointers to avoid copying and slicing.
dynamic_cast<T*>(p)safely casts down a class hierarchy.- It returns
nullptrwhen the cast fails. - dynamic_cast requires a polymorphic class with a virtual function.