Указатели класса против ссылки [дубликаты]

0

Я понимаю основы указателей и ссылок, но самая большая проблема, которую я имею, заключается в том, чтобы решить, когда они должны использоваться (и какие). Основной пример, который я приведу, - одна из основных игр. Предположим, что настройка - это что-то вроде:

  • Новый мир
    • камера
    • карта

World - это указатель, потому что каждый раз, когда игра запускает новое сохранение или загружает существующий, он удаляет мир и загружает новый. Но внутри Мира, только одно существование камеры и карты должно когда-либо существовать и только на протяжении всего Мира. Если мир разрушен, то, очевидно, они должны быть такими же. Однако.. позволяет сказать, что Map необходимо получить доступ к камере (но также и к другим объектам), должна ли камера передаваться по ссылке на карту или как указатель, или? Например, если оно должно быть по ссылке, должно ли оно быть:

map = Map(&camera);
(inside map class) Map(Camera camera) {...}

Или больше нравится:

map = Map(camera);
(inside map class) Map(Camera &camera) {...}

Кроме того, можно сказать, что карта содержит 2D-вектор плит, называемый сеткой. Что-то вроде:

std::vector< std::vector< Tile > > > grid;

Теперь позвольте сказать, что у меня есть класс PathFinder, которому нужна эта сетка. Он должен редактировать плитки напрямую, чтобы изменить значения f, g и т.д. (Для поиска пути). Должен ли этот 2D-вектор быть просто нормальным двумерным вектором Tile, и все это передается ссылкой на PathFinder? Или это должен быть 2D-вектор указателей Tile?

Кроме того, NPC и Player будут иметь currentTile, который является плиткой, в которой они сейчас находятся. Они должны будут иметь ссылку или указатель на эту плитку, чтобы они могли также установить себя как обитатель на этой плитке через что-то вроде этого внутри классов NPC/Player:

currentTile = tile;
currentTile->SetOccupant(this);

Другая проблема возникает, когда я затем уничтожаю эту сетку для загрузки новой карты, как мне легко справиться с тем, чтобы убедиться, что ничто не указывает на Плитки, которые больше не существуют. Нужно ли просто перебирать эти классы и устанавливать currentTile в NULL?

Здесь я начал действительно путаться этим материалом. Любая помощь приветствуется, так как я, очевидно, довольно nooby. @_ @; И извините, если это не тема игры. Если вам нужно переместить его на другой стек, просто сообщите мне или переместите его (если можете). > _ <

Теги:
memory
code-structure

1 ответ

1
Лучший ответ

Рассмотрим класс Map. Вы можете передать камеру по ссылке или в виде указателя. Это действительно не имеет значения. Важно то, что происходит с передачей камеры. Собираетесь ли вы назначить ее члену, который является Camera *? В противном случае установка камеры в конструкторе не будет достигнута. Вам нужно будет указать указатель/ссылку камеры при каждом вызове Карты, требующей камеры.

Для хранения объектов Tile единственный размер std :: vector <> будет очень хорошим. Используя некоторую простую математику, эту сетку черепицы можно пройти довольно легко. Вложение другого вектора внутрь приведет к ненужным накладным расходам. Вот пример алгоритма для этого:

std::vector<Tile> tiles = makeTiles();
for (int y=0; y<mapHeight; y++)
{
   for (int x=0; x<mapWidth; x++)
   {
      Tile tile = tiles.at(x + y*mapWidth);
      tile.doSomethingWithTile();
   }
}

Решение о том, как получить данные о плитки с вашей карты в PathFinder, действительно зависит от того, насколько хорошо вы хотите защитить данные карты. Предоставляя ссылку на все данные плитки, вы по существу делаете ее общедоступной. Поскольку PathFinder должен редактировать отдельные плитки, но не весь массив плиток, лучшим подходом было бы иметь такой метод:

Tile* Map::AccessTile(int tx, int ty);

Таким образом, весь вектор данных плитки не отображается, но PathFinder сможет получить то, что ему нужно. Кроме того, Map :: AccessTile() может быть закрытым, а PathFinder объявлен другом в Map. Другой подход заключается в предоставлении таких методов, как Map :: SetTileF (int tx, int ty, float f). Это может быть утомительным, хотя.

Для NPC и Player доступно аналогичное решение. На самом деле им не нужно иметь прямой доступ к записи, на которой они находятся. Добавьте такой метод, как Map :: SetTileOccupant (Entity * entity) и соответствующий Map :: GetTileOccupant().

Теперь вы беспокоитесь об удалении объектов. Вы должны взглянуть на некоторые эмулированные указатели, предоставленные C++ (в частности std :: shared_ptr <> и std :: weak_ptr <>). Быстрое объяснение этого - shared_ptr - это указатель, который "владеет" объектом, а weak_ptr знает, куда обращаться к объекту, но фактически не "владеет" объектом.

С помощью этих эмулированных указателей вы можете сделать что-то вроде следующего:

//prototype for setWorld
//note that shared_ptr<> casts to weak_ptr<> nicely
Camera::setWorld(std::weak_ptr<World> world);

//setup the camera and world
std::shared_ptr<World> world(new World);
Camera camera;
camera.setWorld(world);

С приведенным выше кодом камера имеет указатель на мир. Если по какой-либо причине мир удаляется, камера может понять это следующим образом:

bool Camera::worldIsValid()
{
   return (this->mWorld.expired() == false);
}

Кроме того, вы инкапсулируете камеру внутри мира, и это, вероятно, то, что вам не нужно делать. Вместо этого камера может быть автономной и просто ссылаться на мир, когда ему нужна информация об этом или Карта, содержащаяся в World.

  • 0
    Только одна последняя прояснение, если вы не возражаете. Должна ли Map быть указателем внутри World (или просто нормальной переменной), если я хочу, чтобы он длился в течение World, а также чтобы можно было передавать его другим членам / классам World? Я предполагаю, что если я не сделаю это указателем, это потеряло бы область?
  • 0
    Вы можете сделать это указателем, но это не имеет значения. Если вы объявите его как карту или карту *, это будет продолжаться до тех пор, пока объект World все еще существует. Очевидно, что если у вас есть Map *, вам придется вручную создать объект с помощью оператора new. Если вы хотите использовать shared_ptr <>, тогда карту необходимо объявить как shared_ptr <Map>.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню