Что не так с вашим кодом?
Ваша функция вернет общий указатель на базовый класс. Это тип возвращаемого значения, который вы определили, поэтому вам нужно уменьшить его, как и вы.
Но вы сделали что-то не так: вы возвращаете ссылку, и эта ссылка будет на временный общий указатель, который будет уничтожен, как только вы вернетесь из GetComponent()
, вызывая UB.
Вам необходимо переопределить вашу функцию и использовать тип возвращаемого значения, удалив &
позади const std::shared_ptr<Component>
:
const std::shared_ptr<Component> Entity::GetComponent(ComponentType type)
Это должно решить вашу проблему, если вы сделали downcast дляправильный тип.
что может быть улучшено в вашем коде?
Но вы должны признать, что уныние может пойти не так. Вся цель dynamic_pointer_cast
- разрешить такую проверку безопасности. Поэтому вместо:
std::dynamic_pointer_cast<Engine::MeshComponent>(testEntity.GetComponent(Engine::ComponentType::Mesh))->SetVertexArray(m_VertexArray);
сделайте это в два шага:
auto pm = std::dynamic_pointer_cast<Engine::MeshComponent>(testEntity.GetComponent(Engine::ComponentType::Mesh));
if (pm)
pm->SetVertexArray(m_VertexArray);
else std::cout << "Oh oh ! Something went wrong"<<std::endl;
Здесь онлайн-демонстрация на минималистском примере. Вы можете поиграть с ним онлайн и поэкспериментировать: добавление & к типу возврата вызовет здесь ошибку времени выполнения.
Полиморфизм не требует приведения.
Если у вас есть код для симуляции и вам приходится выполнять много типов, значит, с дизайном что-то не так.
Во-первых, нет способа создать полиморфное Getcomponent()
, которое позволило бы вам немедленно вызвать функцию, которая не существует для полиморфного типа:
- Здесь вы делаетединамическое приведение в функции, но так как тип возвращаемого значения функции - время компиляции, ваше преобразование в двоичную форму немедленно возвращается в исходное состояние. Вот почему вам нужно (рискованное) снижение с возвращенным указателем.
- Нет способа сделать это с помощью шаблонов. Потому что шаблоны также основаны на типах времени компиляции.
Что вы можете сделать, это определить три разные функции, каждая из которых возвращает ожидаемый тип. Но тогда вы должны быть особенно осторожны, потому что получение указателя таким образом, не будучи уверенным в том, что указатель найден в первую очередь, и не будучи уверенным, что динамическое приведение завершится успешно, может привести к разыменованию nullptr, который является UBи может привести к сбою вашего программного обеспечения.
Рекомендация:
Постарайтесь сделать функции-члены Component
как можно более полиморфными, чтобы пользователю не приходилось знать, является ли он сеткой или нет, когдавызывая функцию. Даункинг должен быть исключением.
Если это невозможно, и если вы все еще предпочитаете использовать специализированные функции (например, GetMeshComponent()
) (что делает ваш дизайн гораздо менее расширяемым), то вам следует предусмотреть некоторую обработку исключений на случай, еслиэта специализированная функция не может предоставить ожидаемый указатель.