0
\$\begingroup\$

I'm trying to access the x and y values from PositionComponent in my MovementComponent but I get this error and I just can't figure out why I get this.

in my Entity class I've got a function GetComponent() that looks like this:

template<typename ComponentType>
ComponentType* Entity::GetComponent() {
    for(unsigned int i = 0; i < m_components.size(); i++) {
        if(ComponentType* cmp = dynamic_cast<ComponentType*>(m_components[i])) {
            return cmp;
        }
    }
    return NULL;
}

m_components is a vector of Component* that looks like this:

std::vector<Component*> m_components;

My MovementComponent looks like this, and I get an error for some reason here:

void MovementComponent::MoveRight() {
    m_ContainingEntity->GetComponent<PositionComponent>()->x++; //I get the error at this line.
}

Error: undefined reference to `PositionComponent* Entity::GetComponent()'

What did I do wrong? I've got a feeling that the solution is really simple and that I just didn't pay much attention.

Entity.h:

#ifndef __ENTITY_H__
#define __ENTITY_H__

#include <vector>
#include <cstddef>

class Component;
class ECSManager;

class Entity {
public:
    void AddComponent(Component* cmp);

    template <typename ComponentType>
    ComponentType* GetComponent();

private:
    friend class ECSManager;
    std::vector<Component*> m_components;
};

#endif // __ENTITY_H__

Entity.cpp:

#include "Entity.h"
#include "Component.h"

void Entity::AddComponent(Component* cmp) {
    m_components.push_back(cmp);
    cmp->m_ContainingEntity = this;
}

template<typename ComponentType>
ComponentType* Entity::GetComponent() {
    for(unsigned int i = 0; i < m_components.size(); i++) {
        if(ComponentType* cmp = dynamic_cast<ComponentType*>(m_components[i])) {
            return cmp;
        }
    }
    return NULL;
}

MovementComponent.h:

#ifndef __MOVEMENTCOMPONENT_H__
#define __MOVEMENTCOMPONENT_H__

#include "Component.h"

class MovementComponent: public Component {
public:
    void MoveRight();
    void MoveLeft();
private:
};

#endif // __MOVEMENTCOMPONENT_H__

MovementComponent.cpp:

#include "MovementComponent.h"
#include "Entity.h"
#include "PositionComponent.h"

void MovementComponent::MoveRight() {
    m_ContainingEntity->GetComponent<PositionComponent>()->x++;
}

void MovementComponent::MoveLeft() {

}
\$\endgroup\$
6
  • \$\begingroup\$ what error do you get exactly? can you post? Also, are you sure your m_ContainingEntity has a PositionComponent? \$\endgroup\$
    – Babis
    Dec 12, 2014 at 12:13
  • \$\begingroup\$ @Babis Added. Yes, in main I added a Position and than a Movement component to an entity. \$\endgroup\$ Dec 12, 2014 at 12:18
  • \$\begingroup\$ is your Entity::GetComponent in a header file (1st code block) and that header file is included in the source file that implements MoveRight? (3rd code block) \$\endgroup\$
    – Babis
    Dec 12, 2014 at 12:18
  • \$\begingroup\$ @Babis MovementComponent.cpp includes "Entity.h"; Entity.h contains GetComponent; MovementComponent.h contains MoveRight() but in MovementComponent.h only "Component.h" is included, in the MovementComponent.cpp "Entity.h" and "PositionComponent.h" are also included. \$\endgroup\$ Dec 12, 2014 at 12:25
  • \$\begingroup\$ you say "Entity.h contains GetComponent". does it contain the declaration or the definition? you say "MovementComponent.h contains MoveRight()" does it contain the declaration or the definition? or both? Point is, wherever MoveRight() is defined or declared, you need to have included the definition of Entity::GetComponent, as appears in the first block. \$\endgroup\$
    – Babis
    Dec 12, 2014 at 12:28

2 Answers 2

1
\$\begingroup\$

Your template definition needs to be in the header file. More specifically:

template<typename ComponentType>
ComponentType* Entity::GetComponent() {
    for(unsigned int i = 0; i < m_components.size(); i++) {
        if(ComponentType* cmp = dynamic_cast<ComponentType*>(m_components[i])) {
            return cmp;
        }
    }
    return NULL;
}

should be in Entity.h

Explanation is here. The compiler needs to have access to the template implementations at the point where you're instantiating the method with PositionComponent as an argument.

\$\endgroup\$
1
  • \$\begingroup\$ I also had to make a virtual function in the Component class to turn on Polymorphism, but now it works, thank you! \$\endgroup\$ Dec 12, 2014 at 13:49
1
\$\begingroup\$

Move the definition of Entity::GetComponent to the header, Entity.h. In general, template definitions must be put into header files. See this related question:

https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged .