3

Below is the perhaps most simple example of a virtual function in C++:

#include <iostream>

class A {
public:
    virtual void f() {
        std::cout << "A";
    }
};

class B : public A {
public:
    void f() {
        std::cout << "B";
    }
};


int main() {
    {
        // calls f() in derived class
        A* a = new B();
        a->f();
    }
    {
        // calls f() in base class
        A a = B();
        a.f();
    }
}

The output of this program is BA. I expected it to be BB, i.e. call the base class in any case. Why does using a base class pointer make a difference here? I didn't find the explanation in the standard.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
  • I believe this is a different problem than slicing. Here, it appears to be a misunderstanding of inheritance, polymorphism and runtime dispatch. He also missed the fact that it works with both 'base class pointers' and 'base class references'. (And there's probably another SO question covering that topic). – jww Jan 12 '14 at 00:26

3 Answers3

11

This is called slicing. A a = B(); creates a copy which is of type A. All information about its source being B is forgotten. The only way to exploit polymorphism is through references or pointers (or mechanisms that allow compile-time polymorphism, like templates or function overloading for example).

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
3

Polymorphism works with pointers because in the case of a pointer(or a reference) you can differentiate between the type of the pointer and the type of the object. Now in the following code:

A a = B();
a.f();

What is happening is called slicing. i.e. the object B() was sliced and its base A() is assigned to a.

Don't forget to make the destructor virtual!

Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
0

The order of function calls in the case of A a = B() is this:

  1. Default constructor of class B is called.
    • A temporary object of type B is created on the stack.
  2. Conversion operator from B to A is called.
    • A temporary object of type A is created on the stack.
  3. Copy constructor of class A is called with the previous object's address as an argument.
    • An non-temporary object of type A is created on the stack.
    • This object will remain in the stack until the function returns.
    • It is an object of type A, hence you get "A" printed and not "B".

To summarize this, here is the "full version" of the line above: A(B()->operator A())

barak manos
  • 29,648
  • 10
  • 62
  • 114