What's wrong with your code ?
Your function will return a shared pointer to the base class. It's the return type that you have defined, so you need to downcast like you did.
But you made something wrong here: you return a reference, and this reference will be to a temporary shared pointer that will be destroyed as soon as you return from GetComponent()
causing UB.
You need to redefine your function and use a value return type, be removing the &
behind const std::shared_ptr<Component>
:
const std::shared_ptr<Component> Entity::GetComponent(ComponentType type)
This should solve your problem if you did the downcast to the correct type.
what could be improved in your code ?
But you should accept that the downcasting can go wrong. The whole purpose of dynamic_pointer_cast
is to allow this kind of safety check. So instead of:
std::dynamic_pointer_cast<Engine::MeshComponent>(testEntity.GetComponent(Engine::ComponentType::Mesh))->SetVertexArray(m_VertexArray);
do it in two steps:
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;
Here an online demo on a minimalist example. You can play with it online, and experiment: adding the & to the return type will cause a runtime error here.
Polymorphism shoud not require casting
If you have poymorphic code and have to do a lot of casting, then there is something wrong with the design.
First, there is no way to make a polymophic Getcomponent()
that would allow you to immediately call a function that does not exist for the polymorphic type:
- Here you do a dynamic casting in the function, but since the return type of the function is compile time, your dynalic casting immediately gets reverted. This is why you need to a (risky) downcasting with the pointer returned.
- There is no way of doing it with templates. Because templates are also based on the compile time types.
What you could do is to define three different functions, each returning the expected type. But then you have to take extra care because getting a pointer this way, not being sure that a pointer is found in the first place, and not being sure that the dynamic cast will succeed, might result in the rdereferencing of a nullptr which is UB and could crash your software.
Recommendation:
Try to design the member functions of Component
as polymorphic as possible, so that the user des not have to know if it's mesh or not when invoking a function. Downcasting should be the exception.
If it is not possible, and if you'd still prefer to go for the specialised functions (e.g. GetMeshComponent()
) (thus making your design much less extensible), then you should foresee some exception handling in case this specialised function is not able to provide the expected pointer.