2015-08-02 6 views
3

Итак, у меня есть вектор, полный всех объектов для моей игры; такие вещи, как объект игрока, объект противника, стены и т. д. Все вещи в векторе - это дети Framework, поэтому я сделал векторный тип Framework, потому что это было самым близким к универсальному типу данных для них.Как хранить разные классы в одном векторе?

Проблема была в том, что она не выполняла переопределенные функции из объектов, которые она хранила. Таким образом, я разобрал его, чтобы узнать, что, по-видимому, я нарезаю объекты, сохраняя их как Framework. Итак, мой вопрос заключается в том, как хранить все эти объекты в одном списке?

Просто для справки, здесь вызывается функции, которые должны быть переопределены.

for (vector<Framework>::iterator num = gameObjects.begin(); num != gameObjects.end(); ++num) 
{ 
    //The current thing 
    Framework currentObject = *num; 
    currentObject.frameEvent(); 
    currentObject.frameEndEvent(); 
    currentObject.drawEvent(); 
} 

Заранее благодарен.

ответ

7

Необходимо указать указатели (Framework*) или std::shared_ptr<Framework> (возможно std::unique_ptr<Framework>) экземпляров. Это позволяет использовать виртуальные вызовы и late binding - это означает, что при обращении к вашим объектам, правильная функция для вызова будет определена во время выполнения. Не забудьте сделать ваши функции virtual

Затем, ваш код (аналогично)

for (vector< Framework* >::iterator num = gameObjects.begin(); num != gameObjects.end(); ++num) 
{ 
    Framework* currentObject = *num; 
    currentObject->frameEvent(); 
    currentObject->frameEndEvent(); 
    currentObject->DrawEvent(); 
} 

Однако я бы рекомендовал н, как это (C++ 11 требуется)

vector< std::unique_ptr<Framework> > gameObjects; 

... 

for (auto & currentObject : gameObjects) 
{ 
    currentObject->frameEvent(); 
    currentObject->frameEndEvent(); 
    currentObject->DrawEvent(); 
} 

Последний (диапазон для цикла) должен работать независимо от используемого типа (в качестве примера можно использовать обычный указатель или shared_ptr или unique_ptr).

Если вы заинтересованы в использовании unique_ptr, обратите внимание, что для того, чтобы хранить их на std::vector, вы должны использовать std::move, так как там может быть только один экземпляр std::unique_ptr (как следует из названия). Consult this answer в случае проблем.

+1

Большое вам спасибо! Это сработало. Но просто интересно, что такое '->'? Это то, как вы вызываете функции из указателей классов? Еще раз, спасибо за помощь! – null

+1

Действительно, вы используете (dot) '.', когда у вас есть объект и' -> ', когда у вас есть указатель (или указательный объект -' std :: shared_ptr' или 'std :: unique_ptr'). – lisu

0

Магазин указателей в вашем векторе, а не фактические экземпляры.

2

Вы должны использовать std::vector<Framework*> или std::vector<std::unique_ptr<Framework>> (или умный указатель по вашему выбору), чтобы избежать нарезки объектов.

Пример кода:

std::vector<std::unique_ptr<Framework>> gameObjects; 

gameObjects.push_back(std::make_unique<Player>(/**/)); 
gameObjects.push_back(std::make_unique<Wall>(/**/)); 

А потом

for (auto& currentObject : gameObjects) 
{ 
    currentObject->frameEvent(); 
    currentObject->frameEndEvent(); 
    currentObject->drawEvent(); 
} 
1

Ну, прямой ответ - нет. Или вы получите обрезку объектов, с которыми вы уже сталкивались. Вам нужно использовать полиморфные способности C++ и хранить общий интерфейс ваших объектов в векторе. Позже вы можете вызвать желаемое поведение, вызвав функции интерфейса, которые имеют различную реализацию в соответствии с фактическим типом объекта.

2

Храните указатели до Framework и используйте полиморфизм.

// Base class 
class Framework { 
    // Make pure virtual if nothing is done here. 
    virtual void frameEvent(); // = 0; 

    // To ensure the derived instances are deleted properly. 
    virtual ~Framework(); // = default; 
}; 

// Some specialized class 
class SomeObject : public Framework { 
    void frameEvent() override; // C++11 style override. 
}; 

std::vector<std::unique_ptr<Framework>> objects; 

// Add a new SomeObject to the list 
objects.emplace_back(new SomeObject()); 
1

Вы должны сделать frameEvent, frameEndEvent и drawEvent виртуальный в Framework.Затем сохраните std::shared_ptr в своем векторе:

std::vector<std::shared_ptr<Framework>> objects; 
objects.push_back(new GameObject()); 

for (vector<Framework>::iterator num = gameObjects.begin(); num != gameObjects.end(); ++num) 
{ 
    //The current thing 
    const Framework& currentObject = **num; // reference, don't copy anything if you don't need to 
    currentObject.frameEvent(); 
    currentObject.frameEndEvent(); 
    currentObject.drawEvent(); 
} 

Обратите внимание, что вы можете хранить unique_ptr в векторе as long as you don't use operations that require copying elements.

Другой вариант, если вы не можете сделать функции виртуальной и знать, какой тип объекта, который вы имеете дело, вы можете бросить первый, а затем вызвать невиртуальные функции:

const PlayerObject& player = static_cast<const PlayerObject&>(*objects[0]); 
player.frameEvent(); 
player.frameEndEvent(); 
player.drawEvent(); 
+0

Ну, вы можете, но есть некоторые ограничения относительно копирования элементов. – ChronoTrigger

+0

Эти ограничения на самом деле помогают вам узнать, где скопированы права собственности на ваши (объявленные как уникальные!) Объекты, что очень полезно, особенно для начинающих. – wasylszujski

1

что вам нужно магазин указатели к вашим объектам. Если у вас есть C++11, то в идеале вы будете хранить их с помощью std::unique_ptr (при условии, что у вас есть один главный вектор ).

C++ 03

std::vector<Framework*> gameObjects; 

for(std::vector<Framework*>::iterator num = gameObjects.begin(); 
    num != gameObjects.end(); ++num) 
{ 
    (*num)->frameEvent(); 
    (*num)->frameEndEvent(); 
    (*num)->drawEvent(); 
} 

C++ 11

std::vector<std::unique_ptr<Framework>> gameObjects; 

for(auto& num: gameObjects) 
{ 
    num->frameEvent(); 
    num->frameEndEvent(); 
    num->drawEvent(); 
} 
0

Другой, возможно, быстрее подход хранить их в отдельных векторах. Это может быть в 50 раз быстрее из-за более высокой эффективности кэширования.