1

I have a basic C++ question about inheritance and virtual methods.

Please regard this code:

#include <iostream>
#include <vector>
using namespace std;

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

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

int main() {
  A a;
  B b;
  vector<A> v;
  v.push_back(a);
  v.push_back(b);

  for (int i = 0; i < v.size(); ++i)
    v.at(i).f();
}

If I execute this code, it prints out

A
A

I do not understand why it does not print

A
B

because the "f" method is declared as virtual. I would like to know why the program behaves in this way.

Thanks in advance

Sven Hager
  • 3,144
  • 4
  • 24
  • 32

6 Answers6

6

Your vector contains A objects:

vector<A> v;

when you push_back a B object into it, the vector copies the A part of it into a new A object. It is the equivalent of doing this:

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

This is called object slicing.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • Ah, I see. I find this behavior very confusing, maybe because I'm coming from the Java world ... – Sven Hager Mar 13 '13 at 16:07
  • 1
    @SvenHager right, that's value semantics for you. In Java "objects" are a kind of pointer/reference, and the equivalent of the vector would hold these references, so there is scope for dynamic dispatch. In C++, you would store smart pointers to the base class to achieve the same. – juanchopanza Mar 13 '13 at 16:10
3

You are slicing the object, you need to use pointers or references for this to behave properly. Example using pointers:

int main()
{
  vector<A*> v;
  v.push_back(new A);
  v.push_back(new B );

  for (int i = 0; i < v.size(); ++i)
    v[i]->f();
}

This will give you the polymorphic behavior you wanted and will have this output:

A
B
Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
2

b is sliced to an instance of A when it's copied for insertion into the vector, you would have to use vector<A*> for this to work as you expect.

Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
0

You should have vector of pointers in order to have polymorphic behavior :)

Shmil The Cat
  • 4,548
  • 2
  • 28
  • 37
  • 2
    you can use std::vector> a; – AnatolyS Mar 13 '13 at 15:56
  • As AnatolyS you could user shared pointers to avoid the hassle of getting rid of the objects (only in the case of dynamic allocation !) or you can use raw/"classic" pointers , but make sure using the array only when the pointers are pointed to _valid_ objects (e.g. not after stack unwinding) – Shmil The Cat Mar 13 '13 at 15:59
0

In C++, only pointers and references to objects behave polymorphically. Your vector contains non polymorphic objects of type A.

try

int main() {
  A a;
  B b;
  vector<A*> v;
  v.push_back(&a);
  v.push_back(&b);

  for (int i = 0; i < v.size(); ++i)
    v.at(i)->f();

Though you need to be aware that those pointers will become invalid when a and b are destroyed (when they go out of scope).

C. M.
  • 100
  • 1
  • 4
0

The vector v contains Objects for Type A. When you push back objects to v these objects are instantiated using the copy constructor of A. Like that each of the objects you call later on the function f for is actually of type A and will never execute B's f().

coltox
  • 360
  • 3
  • 8