Динамическая система инвентаризации C++ — добавление/удаление элементов

Итак, у меня есть текстовая игра на C++. Я написал класс Hero. Я также написал базовый класс под названием Item и его подкласс под названием Weapon (идея состоит в том, чтобы иметь Weapons, Potions, QuestItems и т. д., которые наследуются от класса Item). Таким образом, я могу сделать так, чтобы у моего «Героя» был переменный инвентарь экземпляров предметов. Я хотел, чтобы это было динамично на случай, если Герой получит улучшения для своего хранилища.

Итак, мой класс Hero имеет переменную-член/экземпляр, которая представляет собой динамический массив указателей на элементы. Я объявляю это, а затем перебираю его, устанавливая для каждого элемента новый элемент следующим образом:

Item** inventory = new Item*[15];
for (int i = 0; i < 15; i++)
    inventory[i] = new Item();

Это произошло в функции void Init() класса Hero, которую вызывают все конструкторы (гибкая конструкция). Итак, я попытался написать функцию-член, чтобы добавить элемент в первый «пустой» слот в инвентаре, но это довольно сложно, и я не мог понять, что приводило к сбою моей программы, когда я тестировал ее. В конце концов я понял, что это зависало, когда я пытался получить доступ к элементу массива. Теперь у меня есть только этот фрагмент, который предполагает, что первый элемент пуст, и пытается «добавить» элемент, указанный в этом индексе в массиве:

void Hero::AddToInventory(Item *item)
{
    *inventory[0] = item;
}

А вот как я назвал метод в main():

int main()
{
    Hero *player = new Hero("Joe");
    Item *primaryWeapon = new Item("Dagger");
    player->AddToInventory(primaryWeapon);
    return 0;
}

Любая помощь приветствуется; Я просто немного заржавел в своих динамических объектах и ​​структурах данных на С++. Заранее спасибо!

P.S. Я знаю, что это можно сделать проще с векторами, но я еще не научился их использовать и хотел бы пока придерживаться динамических массивов.


person Zach King    schedule 23.10.2014    source источник
comment
I know this can be done simpler with vectors but I have not learned how to use those yet Так почему бы не выучить их сейчас? На хороших курсах C++ вы все равно сначала изучаете вектор и держитесь подальше от безумия указателей, пока не приобретете опыт, чтобы знать, что вы делаете. Если ваша цель — разработать текстовую игру, не будет ли интереснее сосредоточиться на разработке самой игры?   -  person PaulMcKenzie    schedule 23.10.2014
comment
Извините, в чем именно проблема?   -  person aardvarkk    schedule 23.10.2014
comment
Если вы используете std::vector<Item>, то ваш метод AddToInventory будет void Hero::AddToInventory(Item const & item) { inventory.push_back(item); }. Разве это не проще?   -  person cdhowie    schedule 23.10.2014
comment
Кроме того, вы нигде не предусмотрели освобождение всей той памяти, которую вы выделили, таким образом, вы создали себе убежище для утечек памяти.   -  person PaulMcKenzie    schedule 23.10.2014
comment
Если вы настаиваете на использовании указателей, я бы посоветовал вам сначала разработать класс динамического массива (используя шаблоны), который добавляет, удаляет и т. д. Затем, когда у вас не будет ошибок, используйте его в своем основном приложении. Вы не только узнаете об указателях, вы узнаете о правильном управлении ресурсами, задачах копирования, шаблонах и т. д.   -  person PaulMcKenzie    schedule 23.10.2014
comment
класс динамического массива... например std::vector   -  person Lochemage    schedule 23.10.2014


Ответы (1)


Прежде всего, вы теряете память, сначала инициализируя каждый индекс массива с помощью new Item(), а затем заменяя этот выделенный элемент фактическим элементом позже. Вероятно, для начала лучше просто иметь массив нулевых указателей.

Item** inventory = new Item*[15];
for (int i = 0; i < 15; i++)
    inventory[i] = NULL;

Я считаю, что вы также можете инициализировать массив нулевым значением следующим образом:

Item** inventory = new Item*[15] = {NULL,};

Теперь вы говорите, что у вас есть подкласс Item под названием Weapon, но я вижу, что вы никогда его не используете. Как только вы объявляете new Item(), он относится к типу Item и больше не может трансформироваться в типы производных классов, такие как Weapon(). Итак, в этом случае, чтобы создать кинжальное оружие, оно должно выглядеть примерно так:

Item *primaryWeapon = new Weapon("Dagger");

Наконец, вы получаете сбой во время AddInventoryToItem, потому что вы разыменовываете свой экземпляр Item по заданному индексу, а затем назначаете его указателю на Item вместо прямого Item. Попробуйте это вместо этого:

void Hero::AddToInventory(Item *item)
{
    inventory[0] = item;
}

Также обратите внимание, что если вы просто замените инвентарный индекс новым указателем, вы также можете привести к утечке памяти. Однако, если каждый элемент был инициализирован нулем вместо new Item(), и вы добавили элемент только в пустой слот, это не будет проблемой.

person Lochemage    schedule 23.10.2014
comment
Да, новая часть Item (Dagger) была просто чем-то, что я изменил при тестировании и забыл вернуть обратно. Единственная проблема, с которой я сейчас сталкиваюсь, заключается в том, что в AddToInventory я не могу установить Item** = Item* - person Zach King; 23.10.2014
comment
Это потому, что Item** не является Item*... если вы действительно хотите сохранить указатель и присвоить только данные Item указателю, попробуйте вместо этого *inventory[0] = *item; - person Lochemage; 23.10.2014
comment
Это потому, что вы разыменовываете его с помощью *inventory[0]. Когда вы используете *, вы теперь получаете доступ к значению, поэтому *inventory[0] является элементом в 0, а не указателем на него. Попробуйте просто скопировать значение: invetory[0]-›value = item-›value - person Mark; 23.10.2014