Search code examples
c++object-slicing

Why does returning a virtual class *by value* in C++ alter the v-table?


In the following code I return a derived class CDerived by-value from a function returning its base class, CBase.

For example purposes, CDerived contains a _number field, and I understand that this is "sliced" off during its conversion to the by-value return type, CBase.

However, what confuses me here is that the virtual function Print somehow gets transmuted into its base-class version. In this case the v-table hasn't simply been sliced, it's been altered.

In my actual code _number does not exist, nor does any other data. I would like to be able to return a derived class only for it's v-table, which is declared by the base.

From this question I see that I can "work around" this particular issue by returning a function pointer (or I suppose crafting my own v-table), but why is the v-table being altered in the first place, and is there any way to get around this alteration?.

#include <iostream>

class CBase
{
public:
    virtual void Print() { std::cout << "CBase" << std::endl; }
};

class CDerived : public CBase
{
    int _number;

public:
    explicit CDerived(int n) : _number(n) { }
    virtual void Print() override { std::cout << "CDerived" << std::endl; }
};

CBase GetBase()
{
    return CDerived(42);
}

int main()
{
    CBase base = GetBase();
    base.Print(); // Outputs CBase
    return 0;
}

Solution

  • That's how C++ works.

    You don't return a CDerived object, you return a CBase, copied from the CBase sub-object of the temporary CDerived.