Вектор указателей на базовый класс, странное поведение, вызывающее виртуальные функции - PullRequest
2 голосов
/ 14 мая 2010

У меня есть следующий код

#include <iostream>
#include <vector>

class Entity {
public:
    virtual void func() = 0;
};

class Monster : public Entity {
public:
    void func();
};

void Monster::func() {
std::cout << "I AM A MONSTER" << std::endl;
} 

class Buddha : public Entity {
public:
    void func();
};

void Buddha::func() {
std::cout << "OHMM" << std::endl;
}

int main() {
const int num = 5;  // How many of each to make
std::vector<Entity*> t;

for(int i = 0; i < num; i++) {
    Monster m;
    Entity * e;
    e = &m;

    t.push_back(e);
}

for(int i = 0; i < num; i++) {
    Buddha b;   
    Entity * e;
    e = &b;

    t.push_back(e);
}

for(int i = 0; i < t.size(); i++) {
    t[i]->func();
}

return 0;
}

Однако, когда я запускаю его, вместо того, чтобы каждый класс печатал свое собственное сообщение, они все печатали сообщение «Будда». Я хочу, чтобы каждый объект печатал свое собственное сообщение: монстры печатают сообщение монстра, Будды печатают сообщение Будды.

Что я сделал не так?

Ответы [ 3 ]

13 голосов
/ 14 мая 2010

Вам нужно выделить объекты из кучи с помощью 'new'. Здесь происходит то, что вы создаете временные объекты, берете указатель на эти объекты, а затем эти объекты уничтожаются. Да, это отличается от многих других языков. :)

Вместо этого попробуйте:

int main() {
   const int num = 5;  // How many of each to make
   std::vector<Entity*> t;

   for(int i = 0; i < num; i++) {
      Monster* m = new Monster;
      t.push_back(m);
   }

   for(int i = 0; i < num; i++) {
      Buddha* b = new Buddha;
      t.push_back(b);
   }

   for(int i = 0; i < t.size(); i++) {
      t[i]->func();
   }

   // This is very important!
   for(int i = 0; i < t.size(); i++) {
      delete t[i];
   }

   return 0;
}

Когда вы видите странное поведение, подобное этому, проверьте, чтобы увидеть содержимое фактического вектора. Вы обнаружите, что все ваши слоты имеют одинаковое значение, то есть место в стеке, которое содержит временного монстра, а затем временного Будду.

2 голосов
/ 14 мая 2010

Это происходит потому, что ваши объекты m и b являются локальными для своих соответствующих циклов. После каждой итерации они выходят из области видимости, оставляя вектор, содержащий висячие указатели. В этом случае поведение не определено. Ваша программа вполне могла потерпеть крах.

P.S. Виртуальное наследование - это нечто совершенно иное.

1 голос
/ 14 мая 2010

Здесь у вас есть неопределенное поведение - вы не можете хранить указатели на локальные переменные в векторе с большей областью действия, поскольку переменные улетучатся к тому времени, когда вы призовете к ним виртуальную функцию. Вам нужно будет динамически использовать объекты, для которых вы храните указатели, используя new, и не забудьте освободить их с помощью delete, когда вы закончите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...