Encapsulation is obvious when I have some basic class with a few ints, floats, etc (return by copy). But often I have to either :
1- deal with bigger objects where I can't afford copying, or copying wouldn't make sense
2- polymorphic object which has to be a pointer / reference, so it can't be returned by value.
For example,
class Scene
{
std::vector<Entity*> m_Entities;
//...
//Some other big data
public:
//some member functions
void InitSkyBox(const SkyboxInfo&);
};
class Engine
{
std::unique_ptr<Scene> m_CurrentScene;
public:
void LoadScene(const std::string& sceneStr);
void UnloadScene();
Scene* GetScene() const {return m_CurrentScene.get();}
};
void clientCode(...)
{
Scene* curScene = engine->GetScene();
curScene->InitSkyBox(skyboxinfo);
//...
}
Engine is responsible for the life time of the scene, as it manage loading / unloading etc. Many objects may need to access the scene. For example if I have an object that controls the skyboxes, I could need to get the scene, retrieve the current skybox and modify it. I could also need the scene object to raycast and query a list of entities.
What would be the best approach for this ? If I understand correctly Encapsulation is broken since I returned the scene ptr (handle to internal data) and the client code can do whatever it wants without Engine being aware.
My options would be :
Option A : "Copy" every member function of scene in engine and use delegation instead :
void Engine::InitSkyBox(const SkyboxInfo& info)
{
if(m_Scene.get())
{
m_Scene->InitSkybox(info);
}
}
Now Engine has better control over the scene, but that wouldn't scale well, it could duplicate every methods of scene.
Option B : Return a const pointer instead.
const Scene* const GetScene() const {return m_Scene.get();}
Seems a bit better, but I'm still returning an "handle" to an internal (see Scott Meyers effective c++), and can't call a non const operation.
So, if Scene is a well encapsulated object, how bad is it to return it from the class that is responsible for its lifetime ? I know that objects that refer to the scene could have dangling pointers if the Engine dies before it, but that would be unlikely.
In a game engine, unfortunately, you would also need to retrieve entities / components from everywhere, breaking your scene's encapsulation of entities.
I'm curious to see how you deal with this in your code. Not sure if there is a silver bullet for this :)
Thanks,
X