Home > Mobile >  Why isn't this abstract class working with circular dependency?
Why isn't this abstract class working with circular dependency?

Time:10-22

When I compile my code, i get:

 "src/gameObject.cpp:8:13: error: expected unqualified-id before 'class' GameObject::class Component& getComponent(const std::string &name)"

alongside several other errors of a similar type. I'm not sure if the problem has to do with the abstract class, or the forward declaration of the class. I have tried troubleshooting for the past day and I cannot for the life of me figure out how to fix this dependency. The intention is for "Components" to contain a pointer that points to the gameObject that they are owned by and for gameObjects to contain a list of different implementations of the Component abstract class. Any help would be appreciated.

Here is the code:

Component.h


#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <string>

class GameObject;

class Component{
public:
    
    GameObject* gameObject;

    std::string name;

    virtual void update(const float &dt) = 0;

    virtual void draw() = 0;

    virtual void start() = 0;

    virtual ~Component();
    
};

GameObject.h


#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <vector>
#include <string>
#include <typeinfo>

#include "Transform.h"

class GameObject{
public:
    Transform transform;

    GameObject(const std::string &name, const Transform &transform);

    class Component& getComponent(const std::string &name);

    void addComponent(const class Component &c);

    std::vector<class Component> getAllComponents();

    class Component& removeComponent(const std::string &name);

    void update(const float &dt);

private:
    std::vector<class Component> components;
    
    std::string name;
    
};

gameObject.cpp

#include "Component.h"

GameObject::GameObject(const std::string &name, const Transform &transform)
:name(name), transform(transform)
{}

GameObject::class Component& getComponent(const std::string &name)
{
    for(Component& c : components)
    {
        if(c.name == name)
            return c;
        else
            return NULL;
    }
}

GameObject::void addComponent(const Component &c)
{
    components.push_back(c);
    c.gameObject = this;
}

GameObject::class Component& removeComponent(const std::string &name)
{
    for (int i = 0; i < components.size(); i  ) {
        if(components[i].name == name)
            components.erase(i);
}

GameObject::std::vector<class Component> getAllComponents()
{
    return components;
}

GameObject::void update(const float &dt)
{
    for(Component c : components)
    {
        c.update(dt);
    }
}

CodePudding user response:

First things first, you don't need to added the class key class everywhere a class name is expected. Often it is optional in C unlike C.

Problem 2

Next, you're actually defining a free function named getComponent instead of a member function. For defining the member function outside the class, we first have to be in the scope of the class which we can do by using the scope resolution operator :: as shown below.


class GameObject{
public:
    Transform transform;

    GameObject(const std::string &name, const Transform &transform);
//--v------------------------------------------------>removed class keyword from here
    Component& getComponent(const std::string &name);

    void addComponent(const class Component &c);
//--------------v------------------------------------>removed class keyword from here
    std::vector< Component> getAllComponents();
//-v---------------------------------------------------->removed class keyword from here
    Component& removeComponent(const std::string &name);

    void update(const float &dt);

private:
//--------------v-------------------------->removed class keyword from here
    std::vector< Component> components;
    
    std::string name;
    
};
//-------------------vv---------------------------------->uses scope resolution operator here
Component& GameObject::getComponent(const std::string &name)
{
    for(Component& c : components)
    {
        if(c.name == name)
            return c;
        else
            return NULL;
    }
}

Problem 3

The return type of the member function while implementing it outside the class should be placed before the name of the member function. This means GameObject::void addComponent(const Component &c) is invalid and should be changed to:

vvvv------------------------------------------------>return type void is placed before naming the member function
void GameObject::addComponent(const Component &c)
{

}
vvvvvvvvv---------------------------------------->return type Component& is placed before naming the member function
Component& GameObject::removeComponent(const std::string &name)
{
    for (int i = 0; i < components.size(); i  ) {
        if(components[i].name == name)
            components.erase(i);
}

CodePudding user response:

You are not supposed to put class before a class name each time you are using it. Remove all the class keywords except the ones in a forward-declaration for a class, i.e.

class GameObject;

and those introducing a class definition, i.e.

class GameObject { /*...*/ };

Some of your uses of class are just redundant. Some are potentially dangerous. And others are out-right invalid syntax.


Also, a function returning a Component&, not void, should have a return statement. Otherwise calling it will have undefined behavior. NULL is also not something a function returning a reference can return. A reference must always be bound to an object. There is no NULL state like for pointers.


Also see the other answer for more problems.

  • Related