0

So, I know that there are many questions on stack overflow out there that are trying to handle circular dependencies. But none of those could really answer my question, if it is possible to have two classes know each other, and, more importantly, access information from each other. So, basically, I have read that you could use forward decleration, but with forward decleration, I couldn't access any fields.

Maybe I should also add that I am really new to C++.

But enough talking, let's get to an example:

Let's say we have a class called Scene and a class called EntityBase, which are defined as following:

EntityBase.h

#pragma once
#include <string>
#include "Scene.h"

class EntityBase
{
public:
    std::string entityId;
    Scene scene;


    EntityBase(std::string entityId);

    /* 
    This method will be called when this object is added to the scene 
    */
    void onAddedToScene(Scene* scene);

    /*
    This method will be called when this object is removed from the scene
    */
    void onRemovedFromScene(Scene* scene);
};

Scene.h

#pragma once
#include <vector>
#include <string>
#include "EntityBase.h"

class Scene
{
public:
    std::vector<EntityBase> entities;
    std::string name;

    Scene(std::string name);

    void addToScene(EntityBase& entityBase);
};

The question arises,

How can I print out the name of Scene(and use every method of Scene) while EntityBase can fully access Scene too? So, I'd really appreciate if you'd tell how to do this, because I will probably need to access every field and/or method later.

Budschie
  • 32
  • 6
  • 2
    Every one of your `EntityBase`s has its own instance of `Scene`. This is not what you want. Forget about Java and learn C++ from the ground up. – molbdnilo Jan 18 '21 at 15:14

1 Answers1

1

Since the C++17 standard you don't need the full EntityBase class definition for the Scene class, only a forward declaration:

#pragma once
#include <vector>
#include <string>

class EntityBase;  // Forward declaration

class Scene
{
public:
    std::vector<EntityBase> entities;
    std::string name;

    Scene(std::string name);

    void addToScene(EntityBase& entityBase);
};

You of course need to include EntityBase.h anywhere where the entities vector is used, most notable in the Scene.cpp source file.


Since EntityBase is using an actual instance of Scene you can't do the same with that class and the EntityBase.h header file. Here you must include the Scene.h header file.


If you build targeting an older C++ standard (C++14 or earlier) then you must have the full definition of the EntityBase class for the vector.

As a possible workaround either make entities a vector of pointers to EntityBase; Or make EntityBase::scene a pointer and use forward declaration in the EntityBase.h header file instead. Or a combination of both.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 2
    I believe `std::vector` is UB if `T` is incomplete. Edit : Never mind, this was relaxed in C++17. – François Andrieux Jan 18 '21 at 15:17
  • Does `std::vector entities;` not require a full definition of Scene? – Anton Jan 18 '21 at 15:17
  • 1
    @Anton Since `entities` is a member of the `Scene` class, you can't it without a full definition of the `Scene` class. Or do you mean "does `std::vector entities;` not require a full definition of `EntityBase`"? Then no, or yes. Depends on C++ standard version (as I've now updated the answer with). – Some programmer dude Jan 18 '21 at 15:29
  • 1
    it's also compile-time UB, most implementations were allowing that from time immemorial, those that weren't would fail at compilation time and were rare. And formal limitation could be lifted by using a PIMPl idiom or a private mix-in. – Swift - Friday Pie Jan 18 '21 at 15:34
  • @Someprogrammerdude: Thanks, that answered my question. – Anton Jan 18 '21 at 16:25