1

I have following code on c++:

#include <iostream>;
#include <vector>;

class A
{
public:
    A(int n = 0) : m_n(n) { }

public:
    virtual int value() const { return m_n; }
    virtual ~A() { }

protected:
    int m_n;
};

class B
    : public A
{
public:
    B(int n = 0) : A(n) { }

public:
    virtual int value() const { return m_n + 1; }
};

int main()
{
    const A a(1);
    const B b(3);
    const A *x[2] = { &a, &b };
    typedef std::vector<A> V;
    V y;
    y.push_back(a);
    y.push_back(b);
    V::const_iterator i = y.begin();

    std::cout << x[0]->value() << x[1]->value()
        << i->value() << (i + 1)->value() << std::endl;

    system("PAUSE");

    return 0;
}

The compiler returned result: 1413.

I am little bit confused, because I thought the right result would be 1414 (as the function virtual). How do you explain this program behavior?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Vitali K
  • 577
  • 1
  • 6
  • 12

2 Answers2

6

You are slicing the object, in order to get polymorphism you need to use either a pointer or a reference. This example keeping as close as possible to your original example and using a pointer will act as you wanted:

const A a(1);
const B b(3);

typedef std::vector<const A*> V;
V y;
y.push_back(&a);
y.push_back(&b);
V::iterator i = y.begin();

std::cout << (*i)->value()  << std::endl ;
++i ;
std::cout << (*i)->value()  << std::endl ;
Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
4

To show briefly how the object slicing works here:

const A a(1);
const B b(3);
std::vector<A> y; // so y contains objects of type A

y.push_back(a);   // y[0] is copy-constructed from a
y.push_back(b);   // y[1] is copy-constructed from b

Note that in both push_back calls, it's always an A being constructed, via the automatically-generated A::A(const A&) copy constructor.

Note also that a B is-a A, which is to say b can be implicitly cast to an A and passed into the same copy-constructor.

So, y[1] is an instance of A with the m_n value copied from b, but its virtual function is still A::value. If you have constructor B::B modify the value when it is initialized, instead of when it is returned, you'll see the result you expect.

Useless
  • 64,155
  • 6
  • 88
  • 132