An object deriving from a base class typically contains additional member variables that extend the base class. When by-value assigning or copying an object of the derived type to an object of the base type, those additional member variables are not copied because the base class contains insufficient space in which to store them. This action is commonly called slicing the object because the additional members are "sliced off" the resulting object.
Do not initialize an object of base class type with an object of derived class type, except through references, pointers, or pointer-like abstractions (such as
std::unique_ptr, or std::shared_ptr).
Noncompliant Code Example
In this noncompliant code example, an object of the derived
Manager type is passed by value to a function accepting a base
Employee type. Consequently, the
Manager objects are sliced, resulting in information loss and unexpected behavior when the
print() function is called.
f() is called with the
designer argument, the formal parameter in
f() is sliced and information is lost. When the object
e is printed,
Employee::print() is called instead of
Manager::print(), resulting in the following output:
Compliant Solution (Pointers)
Using the same class definitions as the noncompliant code example, this compliant solution modifies the definition of
f() to require raw pointers to the object, removing the slicing problem.
This compliant solution also complies with EXP34-C. Do not dereference null pointers in the implementation of
f(). With this definition, the program correctly outputs the following.
Compliant Solution (References)
An improved compliant solution, which does not require guarding against null pointers within
f(), uses references instead of pointers.
Compliant Solution (Noncopyable)
Both previous compliant solutions depend on consumers of the
Manager types to be declared in a compliant manner with the expected usage of the class hierarchy. This compliant solution ensures that consumers are unable to accidentally slice objects by removing the ability to copy-initialize an object that derives from
Noncopyable. If copy-initialization is attempted, as in the original definition of
f(), the program is ill-formed and a diagnostic will be emitted. However, such a solution also restricts the
Manager object from attempting to copy-initialize its
Employee object, which subtly changes the semantics of the class hierarchy.
Noncompliant Code Example
This noncompliant code example uses the same class definitions of
Manager as in the previous noncompliant code example and attempts to store
Employee objects in a
std::vector. However, because
std::vector requires a homogeneous list of elements, slicing occurs.
This compliant solution uses a vector of
std::unique_ptr objects, which eliminates the slicing problem.
Slicing results in information loss, which could lead to abnormal program execution or denial-of-service attacks.
Avoid slicing function arguments / return value
|Polyspace Bug Finder|
|CERT C++: OOP51-CPP||Checks for object slicing (rule partially covered)|
|SEI CERT C++ Coding Standard|
|SEI CERT C Coding Standard|
|[Dewhurst 2002]||Gotcha #38, "Slicing"|
|[ISO/IEC 14882-2014]||Subclause 12.8, "Copying and Moving Class Objects"|
|[Sutter 2000]||Item 40, "Object Lifetimes—Part I"|