18.9 — Object slicing

Let’s go back to an example we looked at previously:

In the above example, ref references and ptr points to derived, which has a Base part, and a Derived part. Because ref and ptr are of type Base, ref and ptr can only see the Base part of derived -- the Derived part of derived still exists, but simply can’t be seen through ref or ptr. However, through use of virtual functions, we can access the most-derived version of a function. Consequently, the above program prints:

derived is a Derived and has value 5
ref is a Derived and has value 5
ptr is a Derived and has value 5

But what happens if instead of setting a Base reference or pointer to a Derived object, we simply assign a Derived object to a Base object?

Remember that derived has a Base part and a Derived part. When we assign a Derived object to a Base object, only the Base portion of the Derived object is copied. The Derived portion is not. In the example above, base receives a copy of the Base portion of derived, but not the Derived portion. That Derived portion has effectively been “sliced off”. Consequently, the assigning of a Derived class object to a Base class object is called object slicing (or slicing for short).

Because variable base does not have a Derived part, base.getName() resolves to Base::getName().

The above example prints:

base is a Base and has value 5

Used conscientiously, slicing can be benign. However, used improperly, slicing can cause unexpected results in quite a few different ways. Let’s examine some of those cases.

Slicing and functions

Now, you might think the above example is a bit silly. After all, why would you assign derived to base like that? You probably wouldn’t. However, slicing is much more likely to occur accidentally with functions.

Consider the following function:

This is a pretty simple function with a const base object parameter that is passed by value. If we call this function like such:

When you wrote this program, you may not have noticed that base is a value parameter, not a reference. Therefore, when called as printName(d), we might have expected base.getName() to call virtualized function getName() and print “I am a Derived”, that is not what happens. Instead, Derived object d is sliced and only the Base portion is copied into the base parameter. When base.getName() executes, even though the getName() function is virtualized, there’s no Derived portion of the class for it to resolve to. Consequently, this program prints:

In this case, it’s pretty obvious what happened, but if your functions don’t actually print any identifying information like this, tracking down the error can be challenging.

Of course, slicing here can all be easily avoided by making the function parameter a reference instead of a pass by value (yet another reason why passing classes by reference instead of value is a good idea).

This prints:

I am a Derived

Slicing vectors

Yet another area where new programmers run into trouble with slicing is trying to implement polymorphism with std::vector. Consider the following program:

This program compiles just fine. But when run, it prints:

I am a Base with value 5
I am a Base with value 6

Similar to the previous examples, because the std::vector was declared to be a vector of type Base, when Derived(6) was added to the vector, it was sliced.

Fixing this is a little more difficult. Many new programmers try creating a std::vector of references to an object, like this:

Unfortunately, this won’t compile. The elements of std::vector must be assignable, whereas references can’t be reassigned (only initialized).

One way to address this is to make a vector of pointers:

This prints:

I am a Base with value 5
I am a Derived with value 6

which works! A few comments about this. First, nullptr is now a valid option, which may or may not be desirable. Second, you now have to deal with pointer semantics, which can be awkward. But on the upside, this also allows the possibility of dynamic memory allocation, which is useful if your objects might otherwise go out of scope.

The Frankenobject

In the above examples, we’ve seen cases where slicing lead to the wrong result because the derived class had been sliced off. Now let’s take a look at another dangerous case where the derived object still exists!

Consider the following code:

The first three lines in the function are pretty straightforward. Create two Derived objects, and set a Base reference to the second one.

The fourth line is where things go astray. Since b points at d2, and we’re assigning d1 to b, you might think that the result would be that d1 would get copied into d2 -- and it would, if b were a Derived. But b is a Base, and the operator= that C++ provides for classes isn’t virtual by default. Consequently, only the Base portion of d1 is copied into d2.

As a result, you’ll discover that d2 now has the Base portion of d1 and the Derived portion of d2. In this particular example, that’s not a problem (because the Derived class has no data of its own), but in most cases, you’ll have just created a Frankenobject -- composed of parts of multiple objects. Worse, there’s no easy way to prevent this from happening (other than avoiding assignments like this as much as possible).


Although C++ supports assigning derived objects to base objects via object slicing, in general, this is likely to cause nothing but headaches, and you should generally try to avoid slicing. Make sure your function parameters are references (or pointers) and try to avoid any kind of pass-by-value when it comes to derived classes.

18.10 -- Dynamic casting
18.8 -- Virtual base classes

70 comments to 18.9 — Object slicing

  • Stefan

    At some point you mentioned: "Instead, Derived object d is sliced and only the Base portion is copied into the base parameter".

    But the Base part of Derived contains the vptr which points to Derived vtable. So, when Base portion is copied, the vptr is set to point to Base vtable? If yes, is it done by the copy c-tor?

    I somehow expected that Derived vptr will be copied as it is, from its Base part, to the Base object it is assigned to. I say this as the vote resides in the Base part, which is not sliced off. However, I reckon that, in this case, the new Base object would have been able to call Derived virtual functions via this vptr, which clearly does not happen. Hence my misunderstanding regarding how the vote is changed when slicing occurs.

    • nascardriver

      vtable pointers get initialized when the object is created, and persist. They don't get copied.
      When you create a `Base` from a `Derived`, you're creating a new `Base`, and get a `Base` vtable pointer.
      The vtable is only used when the object is accessed through a pointer or reference. It's unused when the object is accessed directly, as in this example.

  • srt1104

    In here:

    since b is a reference to d2, how is it being re-assigned object d1?

  • salah

    In this example wouldn't the value of *__vptr of "derived" be copied to *___vptr of "base", thus we can access the expected function ?

  • FederAndInk

    You can delete copy construct and assignment of polymorphic classes to avoid these problems by default.
    You can then, if needed, make them virtual and use dynamic_cast.
    But at least not let the compiler generate the default ones

  • Mohammed

    How can the first example has a return of "Base" by having a type of char* on line 12? I mean this:

    By the way why do I have to write two const keywords here?

    • nascardriver

      The first `const` applies to the return type, the second `const` applies to the function. Lesson 4.13 and 8.10.
      "Base" is a `const char*`, the function returns a `const char*`, all cool.

  • // Fix for Slicing vectors [Cpp11], reference wrapper can be used here

    // OUTPUT from above code
    I am a Base with value 5
    I am a Derived with value 6

  • Mihir

    This line:

    results in double deletion.

  • Deepan

    In the The Frankenobject, Base reference object(b) is initialized to d2. again it is assigned to d1. It voilates the statement that "reference variables can be initialized but not assigned". correct me if I am wrong.

  • Nirbhay


    As much as I understand, in the following example (Frakenobject section):

    on  line 5, as b is a Base type reference, b is assigned only 'Base' portion of d2. Then on line 7, d1 is assigned to b(which is of type Base and had previously base part of d2) which now has the base part of d1(overwritten).

    so b ends up with no derived part from either 'd1' or 'd2'..and with base part from 'd1'.

    Then what does the following line mean? and how ?

    "As a result, you’ll discover that d2 now has the Base portion of d1 and the Derived portion of d2."


    • Careful, `b` is a reference. It doesn't store any information, it just references another variable.
      Line 5 doesn't copy anything, it initializes `b` as a reference to `d2`.
      Line 7 copies the `Base` portion of `d1` into `d2` (Because `b` references `d2`).

  • Artun

    At the very end, under "The Frankenobject"

    "As a result, you’ll discover that d2 now has the Base portion of d1 and the Derived portion of d2." should be changed to "As a result, you’ll discover that b now has the Base portion of d1 and the Derived portion of d2."

  • thetinyperson

    Instead of using std::reference_wrapper couldn't we just use pointers like this and not worry about dynamic memory allocation? Or is there some other benefit of using reference_wrapper?

  • Anthony

    I gave Derived a member variable so I could test out the creation of a Frankenobject. Nice.

  • sushmitha

    Hi Alex
    If we pass as ref or ptr of derived class to a base , as you said base class has privilege to  see all derived class data.
    but still why can't we  access data only present in derived class not in  base class  using base class pointers?

    • Alex

      > you said base class has privilege to see all derived class data

      Where did I say such a thing? A base class pointer can point to a derived object, but it can not directly see or access things in the derived part of the class (it can do so indirectly).

  • Sekhar

    Derived d1(5);
    Derived d2(6);
    Base &b = d2;

    b = d1; // this line is problematic

    But b is a Base, and the operator= that C++ provides for classes isn’t virtual by default.

    Is it if operator = can be overloaded for b = d1 statement, so that base part and derived part of d1 object gets copied to d2 object ?

  • Tan

    Hi, thanks for the great tutorial. However, I don't understand why the sliced object cannot access the function of the derived class, isn't it still has a virtual table pointer that points to that function?

    • Alex

      Good question. The sliced object is always a _copy_ of the Base portion of the original object. Because the sliced object is thus of type Base, the virtual table only points to Base functions.

      • Tan

        Hi, thanks for replying. Is the copy of the Base portion not shallow-copied here or each of the subobject will maintain each virtual table pointer of their own? And can I change its behavior by overwriting its copy constructor or copy assignment? Sorry I am confused.

        • Alex

          The sliced item will be shallow copied by default, and will have its own virtual table pointer. You could implement copy constructor/copy assignment to do a deep copy instead of a shallow copy, but because the object will still be an object of the base class type.

          • Nicolai

            Isn't the *__vptr shallow-copied in this case? It means that it would still point to the derived class virtual table?!
            (I suppose that this pointer is reset when object slicing is happening?)

            "Virtual tables are set up per class, not per object, so they are not affected when you copy individual objects." - does that mean there are multiple *__vptr per object instance?.. for each class within the inheritance chain?

  • Aesthete

    I think there is a typo in the following paragraphs.

    "..., you might think that the result would be that d1 would get copied into d2* (must be 'b') -- and it would, if b were a Derived. But b is a Base, and the operator= that C++ provides for classes isn’t virtual by default. Consequently, only the Base portion of d1 is copied into d2* (must be 'b')."

    "As a result, you’ll discover that d2* (must be 'b') now has the Base portion of d1 and the Derived portion of d2"

  • Madhu

    std::cout << "ptr is a " << ptr->getName() << " and has value " << ptr->getValue() << 'n';

    'n' should be '\n'.

  • Hi Alex!

    The first snippet is missing an include to <iostream> and all loops cause a signed/unsigned comparison warning.

  • Winston Lai


    For the code you demonstrated, which is shown below. You are trying to prevent vector slicing by using dynamically allocated object and stored it as pointer within the vector. Is it possible to defined the object and have a pointer pointing toward the object beforehand and then passing into the vector without dynamically allocating it when you initiate the vector.

    • Hi Winston!

      You _could_ do this

      But @p1, @p2 and their copies inside @v will dangle as soon as @b and @d die, so don't do it.

  • Pashka2107

    Hi Alex,
    Not sure at all, but it seems like a typo in the last example, since you were reassigned reference variable. Maybe pointer must be used instead?

    • nascardriver

      Hi Pashka!
      Quick example:

    • Alex

      You can't "reassign" a reference. Once a reference is initialized, the reference is always an alias to whatever it was initialized with.

      So in this case, b is an alias for d2, just with altered type information.

  • Akshay

    Hi Alex,
    While copying derived object to base object we know that only base portion of the derived object gets copied to new base object, but shouldn't that also copy __vptr__ which is pointing to derived's vtable be copied as is into the new base object? if not the case, How and when is __vtpr__'s value is changed while slicing happens?

    Thanks, for the great tutorial!

    • Luhan

      He said in the comments "Virtual tables are set up per class, not per object, so they are not affected when you copy individual objects.". What happens is __vptr__  is created in the Base, and inherited by the Derived classes, which utilizes the __vptr__  inherited to point to their own vtable. At this part Base have access to the __vptr__ , because it's a member of Base. But when you copy (slice the object), the derived part isn't more present, as Alex said "With a pointer or reference, you’re not making a copy -- you’re passing a way of indirectly accessing the object". Because you are slicing the object, the Base class doesn't have more access to the __vptr__ of Derived, which points to the vtable of Derived.

      In resume, the Derived part because of the slicing doesn't exist in that object (I mean the Base object receiving the copy), because when doing assignment, Alex did say that there isn't a default operator= to handle it right, so it's copying only the mutual part these 2 variables have, which is the Base portion of the class.

      Correct me if I'm wrong Alex.

    • Alex

      The virtual pointer isn't a normal member variable, so it's not copied. The virtual pointer in the sliced base class is set (to the base class virtual table) when the sliced base object is created.

  • AMG

    I thought std::vector is supposed to contain entities of the same type, but Base and Derived are different, and so pointers to Base and Derived. Why v.push_back(Derived(6)) (or v.push_back(new Derived(6)) is allowed? Thank you.

    • Alex

      You've always been able to assign values of one type to a vector of a different element type, so long as the value can be converted to the vector's element type.

      Since Derived pointers (or references) can be converted to Base pointers (or references), this is fine -- the value is simply converted to the vector's element type and stored.

  • Panagiotis

    In the section "Slicing and functions" our function's parameter is const Base &base. So, as we have already learnt, the compiler won't let us call any functions that do not have the "const" keyword. I think that our function's declaration should have been like

    for Base class, and

    for Derived class

  • nagarajsherigar

    Base base = derived;
    Assuming assignment operator is called
    wont derived *__vptr copied to base *__vptr?

  • Joe

    Hi Alex,

    Thanks a lot for your tutorials, they are tremendously helpful!

    I have a question which relates to both the concept of virtual functions and the object slicing. Consider the following classes:

    If I put animals of any flavour into m_animalsInStable, is there a way to call the intrinsic functions other than declaring them virtual in the Animal base class? To put it differently, within a member function of Stable can I do something like m_animalsInStable[0].get().getLitresOfMilkPerDay() ?

    • Alex

      You have two main options:
      1) Add a virtual function to the Animal base class, call that, and let it virtually resolve to the most derived class. This generally only makes sense for functions that apply to all Animals, but it's nice because you don't have to know what all the various derived classes are up-front.
      2) Dynamically cast your Animal into a derived object and call whatever function you want directly. The tricky part here is that you have to have some way to determine what derived class the Animal actually is.

      You _could_ create a virtual get() function that returns a pointer (or reference) to the derived object (so Cow would return a Cow* or Cow& to this or *this), but it doesn't really buy you anything that you can't do with a dynamic_cast anyway.

      One way to solve #2 would be to create an AnimalType enum. Then create a virtual getAnimalType() function in Animal. Each class can self-identify by returning the proper enum. You can switch on this enum to do whatever you need to do with a derived-class-specific function. e.g.

  • Hugh Mungus

    Hey Alex,

    Maybe I missed something, but can you explain why passing an object by value causes slicing and passing by reference doesn't?

    • Alex

      When you pass an object by value, a copy of the object is made. The object's type is used to determine what to copy. Thus, if your type is a base type, only the base part will be copied.

      With a pointer or reference, you're not making a copy -- you're passing a way of indirectly accessing the object. That indirection might only see the base part of the object, but the rest of the object is still there.

      • Hugh Mungus

        Ah i see, thank you

      • Gary Wong

        Alex, thank you for your explanation. However, I am still a bit confused.

        QUOTED: "Thus, if your type is a base type, only the base part will be copied."

        *__vptr is part of base type, will the *__vptr of Derived be copied to the Base object?
        If yes, then the *__vptr of Base Object should point to the function of Derived?

        Then why the function of Base is called eventually? Unless there is mechanism of degrading the function call to the Base Class (meaning if the *__vptr is pointing to Derived function, but as there is no Derived function in the Base object, it resolves to Base function)...?

        I really wish that you could help clear up my confusion. Much appreciated!

        • Alex

          > *__vptr is part of base type, will the *__vptr of Derived be copied to the Base object?

          No. The Base class vptr is used, which only points to Base functions.

  • loveu

    Hi alex thanks again for replying so efficiently to my questions!

    for this example, std::vector creates an array of pointers which point to dynamically allocated pointers which point to dynamically allocated objects am I right? So the std::vector deals with the deallocation of dynamically allocated pointers and we have to seperately deal with dynamically allocated objects as you have done so with

    am I going in the right direction?

    • Alex

      Yes, you have it correct. There's just a typo in your sentence, "std::vector creates an array of pointers which point to dynamically allocated pointers which point to dynamically allocated objects am I right"

      It should be: std::vector creates an array of pointers, each of which point to dynamically allocated objects.

  • David

    You explained Franken object by below lines:

        Derived d1(5);
        Derived d2(6);
        Base &b = d2;

        b = d1;

    Here in line b=d1; Base reference b is getting reassigned. Shouldn't it throw compile error ??


    • Alex

      References can't be reassigned. The are set upon initialization and thereafter any assignment to them is an assignment to the referenced object, not a reassignment of the reference itself.

      So in the quoted example, b = d1 means "assign d1 into the object b is referencing (which is d2)". But since b is a Base, it only copies the Base potion of d1 into d2.

  • Jonas

    Hello, Alex! First off, thank you so much for these tutorials! I've been lurking for about a year. Great stuff!
    My question is what happens if I use pop_back() on the vector<std::reference_wrapper<object>>?
    Does it only remove the reference or does it call the object's destructor as well?
    And furthermore, if the object was created using new, is there anything else I have to think about?
    I tried using delete on both the the wrapper and the object (using .get()) but the compiler wouldn't let me, obviously

    • Alex

      Calling pop_back on a reference wrapped element just removes the reference element from the array, it doesn't call any destructors. If the object was created using new, then you'll need to manually destroy it. But if you're creating objects using new, then you should probably be using a std::vector of pointers rather than reference_wrapper.

  • Saiyu

    I didn't notice this before, thank the author!

Leave a Comment

Put all code inside code tags: [code]your code here[/code]