0

Possible Duplicate:
What is the slicing problem in C++?

I've got a simple code as a example of polymorphism and inheritance

class A
{
public:
    int fieldInA;

    void virtual overloadedFunc()
    {
        printf("You are in A\n");
    }
};

class B : public A
{
public:
    int fieldInB;

    void overloadedFunc()
    {
        printf("You are in B\n");
    }
};

void DoSmth(A* a)
{
    a->overloadedFunc();
}

void DoSmthElse(A a)
{
    a.overloadedFunc();
}
int _tmain(int argc, _TCHAR* argv[])
{
    B *b1 = new B();
    B b2;
    //Breakpoint here
    DoSmth(b1);
    DoSmthElse(b2);
    scanf("%*s");
    return 0;
}

When I stop in breakpoint, the values of _vfptr[0] of b1 and _vfptr[0] of b2 are the same (SomeAddr(B::overloadedFunc(void))). After passing b1 as parameter in DoSmth(), _vfptr[0] of local variable a is still someAddr(B::overloadedFunc(void)), but _vfptr[0] of a in DoSmthElse is now someAddr(A::overloadedFunc(void)). I'm sure this is some my misunderstaning of function overloading concept, but I couldn't understand, why in first case I saw "You are in B" and in second "You are in A". The same with A *b1 = new B(); DoSmth(b1); // You are in B, why?

Community
  • 1
  • 1

2 Answers2

5

First off, you need to get your terminology right! You didn't overload any functions, you overrode them:

  • Overloading means that you have the same function name with different types of arguments. Choosing the correct overload is a compile-time operation.
  • Overriding means that you have class hierarchy with a polymorphic (in C++ virtual) function and you replace the function being called with a function applicable to object of a more specialized class. You override the original meaning. Choosing the correct override is a run-time operation, in C++ using something similar to a virtual function table.

The terms are confusing enough and to make things worse, these even interact: At compile time the correct overload is chosen which way end up calling virtual function which may, thus, be overridden. Also, overrides a derived class may hide overloads otherwise inherited from the base class. All this may make no sense if you can't get the terms straight, though!

Now, for your actual problem, when you call DoSmthElse() you pass your object b2 by value to a function taking an object of type A. This creates an object of type A by copying the A subobject of your B object. But since B is derived from A, not all of B gets represented, i.e., the A object you see in DoSmthElse() doesn't behave like a B object but like an A object. After all, it is an A object and not a B! This process is typically called slicing: you slice off the parts of the B object which made it special.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
1

To obtain polymorphic behaviour you need to call virtual functions on a pointer or reference to the base class, not an instance of a base class. When you call this function

void DoSmthElse(A a)

you passed an instance of B. This is pass by value and so the argument is a sliced copy of your B instance that you pass to it. Essentially this means that all of the properties of B that are common to A are preserved in this copy and all of the properties of B that are specific to B and not to A are lost. Because of this, object within DoSmthElse() that the function overloadedFunc() is called on is now exclusively of type A (and no longer of type B) and so of course A::overloadedFunc() is called.

In the first case with DoSmth when the argument is of type pointer to base class, the polymorphic behaviour is obtained as you would expect - the B* argument gets passed to the function and a copy of this pointer is made that is now of type A*. Although the copy has been cast to an A*, the object pointed to is still of type B. Because the object pointed to is of type B the fact that it is accessed via a pointer to it's base class, ensures that the function B::overloadedFunc() is actually called when the line

a->overloadedFunc();

is executed, because the virtual function overloadFunc() is overridden by class B. Had class B not implemented it's own distinct version of the base class virtual function (i.e. Class B overrides the class A functionality) then the base class version would have been called instead.

mathematician1975
  • 21,161
  • 6
  • 59
  • 101