Treycos Treycos - 1 month ago 17
C++ Question

Polymorphism with smart pointers using templates

I'm having trouble putting a shared_ptr of sf::Text, sf::Sprite and sf::Text into an array of shared_ptr

sf::Drawable is the mother class of all the above and is abstract

Here's the game engine function:

GameEngine.h

template<class T>
void add(std::shared_ptr<T> actor);


GameEngine.cpp

template<>
void GameEngine::add<sf::Drawable>(std::shared_ptr<sf::Drawable> actor)
{
drawables.insert(actor);
}


Rendering.cpp

void Rendering::addDrawable(std::shared_ptr<sf::Sprite> sprite, sf::Vector2i texture_rect, const char* texture_name)
{
sf::Texture* _texture = engine.lock()->getGameData().getTexture(texture_name);
if (_texture) {
sprite->setTexture(*_texture);
sprite->setTextureRect(sf::IntRect(0, 0, texture_rect.x, texture_rect.y));
//What do i have to put in the below function?
engine.lock()->add(sprite);
}
}


I'm getting the following error in VS 2015:

1>Rendering.obj : error LNK2019: symbole externe non résolu "public: void __thiscall GameEngine::add<class sf::Sprite>(class std::shared_ptr<class sf::Sprite>)" (??$add@VSprite@sf@@@GameEngine@@QAEXV?$shared_ptr@VSprite@sf@@@std@@@Z) référencé dans la fonction "public: void __thiscall Rendering::addDrawable(class std::shared_ptr<class sf::Sprite>,class sf::Vector2<int>,char const *)" (?addDrawable@Rendering@@QAEXV?$shared_ptr@VSprite@sf@@@std@@V?$Vector2@H@sf@@PBD@Z)
1>Rendering.obj : error LNK2019: symbole externe non résolu "public: void __thiscall GameEngine::add<class sf::Shape>(class std::shared_ptr<class sf::Shape>)" (??$add@VShape@sf@@@GameEngine@@QAEXV?$shared_ptr@VShape@sf@@@std@@@Z) référencé dans la fonction "public: void __thiscall Rendering::addDrawable(class std::shared_ptr<class sf::Shape>,char const *)" (?addDrawable@Rendering@@QAEXV?$shared_ptr@VShape@sf@@@std@@PBD@Z)
1>Rendering.obj : error LNK2019: symbole externe non résolu "public: void __thiscall GameEngine::add<class sf::Text>(class std::shared_ptr<class sf::Text>)" (??$add@VText@sf@@@GameEngine@@QAEXV?$shared_ptr@VText@sf@@@std@@@Z) référencé dans la fonction "public: void __thiscall Rendering::addDrawable(class std::shared_ptr<class sf::Text>,char const *,char const *,class sf::Color)" (?addDrawable@Rendering@@QAEXV?$shared_ptr@VText@sf@@@std@@PBD1VColor@sf@@@Z)


Is there a way to put a shared pointer of a subclass into an array of shared pointers of its mother class?

EDIT:

An answer said that:


Just because Sprite is a subclass of Drawable, does not mean that
shared_ptr<Sprite>
is a subclass of
shared_ptr<Drawable>
.


Then why can i do this?

class A{};

class B : public A {};

int main() {
std::vector<std::shared_ptr<A>> ar;
ar.push_back(std::make_shared<B>());
return 0;
}

Answer

Just because Sprite is a subclass of Drawable, does not mean that shared_ptr<Sprite> is a subclass of shared_ptr<Drawable>.

When the compiler sees this:

engine.lock()->add(sprite);

it looks for a member function add(shared_ptr<sf::Sprite>) following the overload resolution rules.

Even though shared_ptr<Sprite> is not a subclass of shared_ptr<Drawable>, there is an implicit conversion available, so it would be a candidate.

However this:

template<class T>
    void add(std::shared_ptr<T> actor);

provides a declaration of the function for any type, but no definition. Therefore it provides an exact match and will be chosen by the compiler. That is why you get linker errors.

One way to solve this is to use std::static_pointer_cast, like this:

engine.lock()->add(std::static_pointer_cast<Drawable>(sprite));

I would also reconsider if/why you need the template above - I can't see what purpose that is serving, other than to give you link time errors instead of compile time errors.