2013-05-13 1 views
1

я следующий код на 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; 
} 

Компилятор возвращаемый результат: 1413.

Я немного смущен, потому что я думал, что правильный результат был бы 1414 (как функция виртуальная). Как вы объясните это поведение программы?

+3

Не помещайте ';' в конце своих '# include'-директив. – Fabien

+0

@Fabien Я удивлен, что программа скомпилирована. – imulsion

ответ

6

Вы являетесь объектом slicing, для того чтобы получить полиморфизм, вам необходимо использовать либо pointer, либо reference. Этот пример держать как можно ближе к исходному примеру и с помощью pointer будет действовать, как вы хотели:

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 ; 
+0

Большое спасибо. Понятно теперь. –

4

Кратко показать, как объект нарезка работает здесь:

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 

Обратите внимание, что в обоих push_back звонки, всегда создается A через автоматически созданный конструктор копирования A::A(const A&).

Заметим также, что Bявляется разновидностьюA, что сказать b может быть неявно приведен к A и передается в тот же экземпляр-конструктор.

Так, y[1] является экземпляром A со значением m_n копируется из b, но его виртуальная функция по-прежнему A::value. Если у вас есть конструктор B::B, измените значение, когда оно инициализировано, а не когда оно будет возвращено, вы увидите ожидаемый результат.