2016-02-14 2 views
0

Я пытаюсь создать карту unique_ptr базового класса (сущности), где хранится только уникальный идентификатор для идентификации моих объектов. Теперь я хотел создать разные производные классы (например, плейер, плитку и т. Д.), Которые должны быть получены из базового класса, чтобы иметь уникальную идентификацию.Получить указатель базового класса для использования функций производного класса

Как передать местоположение памяти unique_ptr как возвращаемое значение, не перемещая его из моей карты? Моя мысль состоит в том, чтобы использовать память-местоположение базового класса, чтобы получить доступ к производным функциям, передавая производные классы в мою карту.

P.S. I'm в настоящее время работает над своей собственной игровой двигатель (до сих пор своего рода новым для CPP)

Это мой текущий EntityManager WIP:

EntityManager.hpp

#pragma once 
#include "TSingleton.hpp" 
#include "Entity.hpp" 
#include <map> 
#include <iostream> 
#include <memory> 

#define g_pEntityManager EntityManager::Get() 

class EntityManager : public TSingleton<EntityManager> 
{ 
public: 
    EntityManager(); 
    ~EntityManager(); 
    // add entity to entity-manager and returns id in entityManager 
    int addEntity(std::unique_ptr<Entity> gameObject); 

    // get pointer to entityManager 
    std::map<int, std::unique_ptr<Entity>> getEntityManager() { return m_EntityManager; }; 

    // destroy entity 
    void killEntity(int entityId); 

    // get entity 
    std::unique_ptr<Entity> getEntity(int entityId); 
private: 
    int m_nEntityCounter = 0; 

    std::map<int, std::unique_ptr<Entity>> m_EntityManager; 
}; 

EntityManager.cpp

EntityManager::EntityManager() 
{ 
} 


EntityManager::~EntityManager() 
{ 
} 

int EntityManager::addEntity(std::unique_ptr<Entity> gameObject) 
{ 
    int size = m_EntityManager.size(); 
    gameObject->setID(size); 
    // add entity-object to EntityManager and increment entity_id; 
    m_EntityManager.insert(std::make_pair(size, std::move(gameObject))); 
    std::cout << "Entity added! " << m_EntityManager.size() << std::endl; 
    m_nEntityCounter ++; 
    return size; 
} 

void EntityManager::killEntity(int entityId) 
{ 
    std::map<int, std::unique_ptr<Entity>>::iterator it = m_EntityManager.find(entityId); 

    if (it != m_EntityManager.end()) 
    { 
     m_EntityManager.erase(it); 
    } 
    else 
     std::cout << "Couldn`t kill Entity with id: " << entityId << " , because there is no Entity with this id in EntityManager" << std::endl; 
} 

std::unique_ptr<Entity> EntityManager::getEntity(int entityId) 
{ 
    std::map<int, std::unique_ptr<Entity>>::iterator it = m_EntityManager.find(entityId); 
    if (it != m_EntityManager.end()) 
    { 
     if (it->second != nullptr) 
     { 
      std::unique_ptr<Entity>& found = it->second; 
      return std::move(found); 
     } 
     else 
      std::cout << "Pointer to object is NULL!" << std::endl; 
    } 
    else 
     std::cout << "Couldn`t find Entity with id: " << entityId << " in EntityManager" << std::endl; 
} 
+0

Вы можете использовать 'std :: unique_ptr :: get' для извлечения необработанного инкапсулированного указателя. Это то, о чем вы просите? – paddy

+0

Возможно, вы должны создать SSCCE, описывающий, что вы пытаетесь сделать, потому что это очень неясно. Вы пытаетесь передать «unique_ptr» для кого-то еще, чтобы заполнить? Или вы пытаетесь передать значение, которое оно содержит, не обходя владение? Если это последний, возможно, вы хотите использовать 'shared_ptr'. – kfsone

+0

Я просто пытаюсь получить необработанный указатель и надеяться, что я могу получить доступ к функциям моих производных классов с помощью этого необработанного указателя. @paddy, да ... пытался использовать get() раньше, но, к сожалению, забыл о возврате типа Entity * вместо std :: unique_ptr thy – cFx

ответ

1

Просто невозможно вернуть значение unique_ptr без его перемещения.

Что вы можете сделать, однако, одна из этих вещей:

Возврат сырой указатель:

Entity* EntityManager::getEntity(int entityId) 
{ 
    return it->second.get(); 
} 

возвращает ссылку на unique_ptr:

std::unique_ptr<Entity>& EntityManager::getEntity(int entityId) 
{ 
    return it->second; 
} 

"Проблема" с возврат по ссылке - это то, что вам всегда нужно вернуть действительную ссылку на объект. Раньше я использовал стратегию создания, например, объекта static std::unique_ptr<Entity> EmptyEntity, и getEntity вернет его, если он не сможет найти его на карте.

Например:

static std::unique_ptr<Entity> EmptyEntity; 

std::unique_ptr<Entity>& EntityManager::getEntity(int entityId) 
{ 
    if (it == container.end()) 
     return EmptyEntity; 

    return it->second; 
} 

Другим решением было бы возвращение unique_ptr по указателю, и вернуть nullptr, если он не может найти любой объект. Если вы это сделаете, вместо этого проще использовать Entity* EntityManager::getEntity().

+0

Спасибо за ваш ответ, в настоящее время пытаемся =) – cFx

+0

Работает как шарм. .. еще раз спасибо! Но на самом деле мои преимущества при использовании std :: unique_ptr & над необработанным указателем Entity? При отбрасывании на производный класс было легко отличить Entity * от моего производного класса ... но с проблемами бросать unique_ptr в производный класс. – cFx

+0

Я бы сказал, что нет. В конце дня, в обоих сценариях вам нужно убедиться, что указатель не имеет значения nullptr перед его использованием. Единственный случай, когда вам нужно вернуть ссылку на unique_ptr, - это если вы собираетесь его модифицировать (что иногда необходимо). – Jts