Search code examples
c++vtableobject-slicingvptr

Virtual Table and Object Slicing


In object slicing, when a derived class object is copied to a Base class object, does the _vptr of Derived class also get copied to _vptr of Base class, like other members of class Base? If not, why?

class Base {
public :
    virtual void Display() { cout << "In Base" << endl; }
};
class Derived:public Base {
public:
    void Display() { cout << "In Derived" << endl; }
};
int main()
{
    Derived objD;
    Base objB;
    objB = objD;
    objB.Display();
}

I have observed the following result for the above snippet.

Output
In Base

Solution

  • The vptr is NOT copied. Let's try to reason about why.

    Looking at your main function:

    Derived objD;
    Base objB;
    objB = objD;  // <-- HERE
    objB.Display();
    

    In line 3, you are assigning objD to objB. This is actually calling Base's assignment operator (which is automatically defined):

    Base& operator=(const Base& other)
    

    and it is being passed objD as a Base&. So, your question becomes, "Does the assignment operator copy the vptr"? The answer is, "no". The default assignment operator only copies fields on the class.

    You may then ask, "Why wouldn't it copy the vptr too?" The reason is that, if it copied the vptr, methods on the Base class would end up using methods implemented on the Derived class. However, in full generality, those methods could use data members that only exists on the Derived class (and that don't exist on the Base class). Calling those methods would therefore be nonsensical (the data logically doesn't exist on the Base class), and so the language rightly chooses not to do this.

    The main issue is that, when you assign the Derived class to the Base class, the variable you're assigning to only holds the fields for the Base class, so the fields in the Derived class that aren't in the Base class are not copied. Therefore, methods from the Derived class won't make sense when called on the Base class.

    Note that this isn't the case if, instead, you were to assign a Base pointer or a Base reference to the Derived class. In that case, the original Derived class instance still exists. It's sitting in memory somewhere and has all the Base+Derived class fields. Therefore, methods for the Derived class called on that instance will have access to those fields, and so being able to call those methods still makes sense.

    This is why, in C++, to do polymorphism (via virtual methods), you need to use a reference or pointer. See here for a similar discussion: Why doesn't polymorphism work without pointers/references?