Как правильно создать базовый класс в C ++? - PullRequest
0 голосов
/ 03 января 2012

Я изучаю C ++ самостоятельно, "создавая" RPG. Тем не менее, я застрял в момент создания класса с именем Item, который будет базовым классом для всех игровых элементов (или, если бы это было в Java, интерфейс). Вот мой код:

class Item {

    public:

    virtual const char* GetName() = 0;
};

Я прочитал кое-что о «чисто виртуальных» функциях, которые я использую.

Класс моего персонажа, где я использую свой предмет:

class Character {

  // some code...

  void ConsumeItem(Item item);

}

Но gcc выдает мне эту ошибку:

g++ -Wall -o adventure character.cpp adventure.cpp
In file included from adventure.cpp:3:0:
character.h:36:24: error: cannot declare parameter ‘item’ to be of abstract type ‘Item’
item.h:4:7: note:   because the following virtual functions are pure within ‘Item’:
item.h:11:22: note:     virtual const char* Item::GetName()

Я очень новичок в ООП в C ++, так как он сильно отличается от Java. Я уже читал некоторые статьи об абстрактных классах в C ++, но просто не могу заставить его работать.

Подскажите, пожалуйста, правильный путь для достижения этой цели?

Ответы [ 6 ]

3 голосов
/ 03 января 2012

В Java, делая что-то подобное, создаст ссылку на Item, который затем можно назначить экземпляру конкретного подкласса.

Однако в C ++ Item item создаст экземпляр Item, что недопустимо, поскольку Item содержит чистую функцию virtual.

Чтобы избежать этой проблемы, необходимо сделать item указателем или ссылкой, как:

void ConsumeItem(Item *item);
2 голосов
/ 03 января 2012

Как правило, если у вас есть иерархия классов, вы хотите использовать ссылки или [умные] указатели на ваши объекты.В ваших фрагментах кода Item является абстрактным базовым классом и, следовательно, не может быть создан.Однако параметр Item в вашей функции ConsumeItem передается по значению: без «&» и «*» объекты являются значениями в C ++.Возможно, вы захотите передать параметр, используя один из них:

  • void ConsumeItem(Item& item) // передать по ссылке
  • void ConsumeItem(Item const& item) // передать неизменяемый объект по ссылке
  • void ConsumeItem(Item* item) // пройти с помощью указателя
  • void ConsumeItem(std::shared_ptr<Item> item) // передать с помощью умного указателя

Кстати, что-то, что вы не могли бы легко получить:В вашем базовом классе есть любая виртуальная функция, поэтому вы также можете использовать виртуальный деструктор!В противном случае вы почти наверняка столкнетесь с неопределенным поведением, которое обычно является плохим.То есть в вашем Item классе добавьте:

virtual ~Item() {} // can also be defined out of line but always has to be defined
0 голосов
/ 03 января 2012

Чтобы использовать полиморфизм в C ++, вам нужно использовать указатели (или ссылки, но я собираюсь пока игнорировать это).

Вы должны хранить свои полиморфные объекты как указатели, передавать их как указателии т. д.

Модифицированный ConsumeItem будет выглядеть следующим образом:

class Character {

  // some code...

  void ConsumeItem(Item* item);

}

Это будет улучшено за счет использования shared_ptr во избежание утечек памяти.

class Character {

  // some code...

  void ConsumeItem(std::shared_ptr<Item> item);

}

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

0 голосов
/ 03 января 2012

Вы не можете создавать экземпляры классов, которые содержат чисто виртуальные методы, и Item item будет таким экземпляром un.Вы можете создать указатели для них, так что Item *item будет работать.

0 голосов
/ 03 января 2012

Make ConsumeAccept получает ссылку (или указатель) на Item:

void ConsumeItem(Item& item);

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

Убедитесь, что вы понимаете, какие указатели, ссылки итипы значений в C ++.В Java все объекты обрабатываются как ссылки без дополнительного знака (например, &) для обозначения этого.Разница имеет решающее значение.

0 голосов
/ 03 января 2012

Поскольку Item является абстрактным классом, вы не можете использовать его экземпляр, вам следует использовать либо указатель *, либо ссылку & на него.

В вашем случае вы передаете его экземпляр, вместо этого вы должны передать указатель:

class Character {

  // some code...

  void ConsumeItem(Item* item);

}

Таким образом, вы фактически передаете указатель на объект класса, который НЕ является абстрактным и унаследован от Item.

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