2013-12-03 3 views
4

Я кодировал простую настольную игру, чтобы изучать концепции C++ на практике. Я внедрил доску: она состоит из плиток, каждый из которых является дочерним классом, наследующим от родительского класса. Плата - это класс, в котором есть вектор плит.Доступ к функциям дочернего класса в родительском классе

Существует несколько видов плиток. Некоторые из них могут быть куплены игроками. Есть несколько различных видов покупаемых плиток, а также с различными свойствами, поэтому я счел это милым сделать базовый класс TileOnSale для плиток, которые можно купить, и создать дочерние классы реальных типов, два из которых я представил в приведенном ниже коде ,

Теперь моя проблема в том, как я могу получить доступ к функциям дочерних элементов, которые не определены в родительском классе (TileOnSale)? Совет получает инициализацию со всеми видами различных фрагментов, поэтому я могу извлечь Tile оттуда, используя функцию getTile (int location). Однако это интерпретируется как просто Плитка, а не TileOnSale или StreetTile. Я не знаю, как это понять.

Итак, есть ли устойчивый или даже лучший, аккуратный способ сделать это? Могу ли я создать шаблон или что-то, чтобы удержать объекты Tile, которые могут быть StreetTiles или StationTiles или что-то еще, что является Плиткой? Или я должен просто перепроектировать структуру класса?

Вот костяной код костей. Я попытался предоставить только то, что необходимо для понимания вопроса. Кроме того, первоначально Tile и Board были в своих заголовочных файлах. Я решил, что не обязательно показывать класс Player, у которого есть вектор принадлежащих TileOnSale объектов, но который сохраняет ту же проблему доступа, что и Board.

// Board.h 
#include "Tile.h" 
typedef vector<Tile> Tiles; 

class Board 
{ 
public: 
    Board(); 
    ~Board(); 
    Tile   getTile(int location); 
private: 
    Tiles   tiles; 
}; 

// Tile.h 
class Tile 
{ 
public: 
    Tile(); 
    ~Tile(); 
protected: 
    tileType tile_type; // this is enum containing unique type 
    string  description; 
}; 

class TileOnSale : public Tile 
{ 
public: 
    TileOnSale(); 
    ~TileOnSale(); 

    virtual int getRent() const { return 0; }; 
}; 

class StreetTile : public TileOnSale 
{ 
public: 
    StreetTile(); 
    ~StreetTile(); 
    int getRent() override; 
    void buildHouses(int number); 
private: 
    int houses; 
}; 

class StationTile : public TileOnSale 
{ 
public: 
    StationTile(); 
    ~StationTile(); 
    int getRent() override; 
}; 

EDIT: добавлен потенциально разъясняющий комментарий к коду.

+1

Не уверен, что это то, что вы хотите. Но посмотрите http://stackoverflow.com/questions/14948957/c-type-casting-base-object-to-derived-object –

+0

Да; это похоже на то, что я намерен. Спасибо, я вижу, есть несколько способов сделать это. – Twistor

+0

Это же замечание кстати: вы должны использовать вектор . –

ответ

2

Возможно, вы захотите взглянуть на visitor pattern.

По существу, посетитель позволяет добавлять новые виртуальные функции в семейство классов без изменения самих классов; вместо этого создается класс посетителей, который реализует все соответствующие специализации виртуальной функции. Посетитель берет ссылку на экземпляр в качестве входных данных и реализует цель посредством двойной отправки.

Двойная отправка означает, что вы фактически вызываете виртуальную функцию дважды: сначала на тему, которая в свою очередь полиморфно вызывает посетителя.

В вашем случае есть только один метод, а именно строительство домов, но вы можете захотеть добавить другие позже (например, рисовать их на экране).Учитывая текущий пример, вы должны добавить этот метод для плитки и StreetTile:

virtual void accept(Visitor& v) { v.visit(*this); } 

Это реализация посетителей базового класса:

class Visitor { 
public: 
    virtual void accept(Tile& t) = 0; 
    virtual void accept(StreetTile& t) = 0; 
}; 

После этого вы можете реализовать класс Builder:

class Builder: public Visitor { 
private: 
    int numberOfHouses; 
public: 
    Builder(int n): numberOfHouses(n) {} 
    virtual void accept(Tile& t) {} 
    virtual void accept(StreetTile& t) { 
     t.buildHouses(numberOfHouses); 
    } 
}; 

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

Builder b(10); 
for (Tile tile : tiles) { 
    tile.accept(b); 
} 
+0

Woah, я не знал об этом, но он выглядит круто. Я действительно хочу добавить больше методов (sellHouses и т. Д.), Показав только одно, потому что buildHouses было достаточно, чтобы объяснить эту идею. Я взгляну на ссылку. – Twistor

+0

Разве это получилось? –

+0

Пока нет, потому что я еще не успел посмотреть на это. Однако я думаю, что сначала попробую этот подход, потому что он выглядит так хорошо. – Twistor

1

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

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

Наличие идентификатора типа также хорошо подходит для целей отладки.

+0

Я полагаю, что если бы я применил функцию для каждого типа возвращаемого значения, которая могла бы работать, поскольку у меня есть менее десяти разных типов детей для Плитки. Это было бы не так аккуратно, хотя код в них был бы почти идентичным. =) Кроме того, у меня уже есть тип для каждого Tile (enum tileType), хотя я, похоже, забыл включить его определение. – Twistor

Смежные вопросы