1

First of all, I beg your pardon if this question has been already answered, but I simply cannot be sure of my choice.

I am working on a C++ game engine and I want it to be according to the modern standards. I wrote it in OOP manner and I have a main class called ENGINE. Inside it, there are a couple of class instances that represent specific subsystems: WINDOW, D3D11_RENDERER, etc. I also have a logging system (LOGGER) which must be available to all subsystems.

Now, this global access to the logger poses me a problem. I am uncertain whether I should declare it as static, outside the ENGINE class and have a function that returns a reference to it or instance it inside ENGINEand make all subsystems point to it.

To give you a better idea of what I am talking about, I posted simplified versions of these scenarios (take into account that I removed a lot of meaningless functions).

First solution:

class LOGGER {...};

LOGGER* GetLogger()
{
    static LOGGER Logger;
    return &Logger;
}

// Just one example.
class WINDOW
{
    void Function()
    {
        GetLogger()->Write();
    }
};

class ENGINE
{
private:
    WINDOW Window;
}

Note that Irrlicht engine does it like this:

class Printer
{
public:
    static void Write();
    static LOGGER* Logger;
};

And it can be globally accessed like this:

os::Printer::Write();

Second solution:

class LOGGER() {...};

// Same example.
class WINDOW
{
public:
    void Initialize(LOGGER* pLogger)
    {
        Logger = pLogger;
    }

    void Function()
    {
        Logger->Write();
    }

private:
    LOGGER* Logger;
};

class ENGINE
{
public:
    void Initialize()
    {
        Window.Initialize(&Logger);
    }

private:
    WINDOW Window;
    LOGGER Logger;
}

I do not know which is the best solution and I would be glad if you could point me to the right one. Thank you in advance.

featherless biped
  • 163
  • 1
  • 5
  • 16

1 Answers1

4

I think this diagram represents better what you need:

enter image description here

Your components should be log-agnostic, as their function don't depend on logging capabilities. This function should be delegated to the engine.

The engine itself can contain a Logger component, which handles the de facto logging.

So let's see some basic code:

class Engine {
    private:
        Logger& mLogger;
        EngineComponent mComponents[10];
    public:
        Engine(Logger& logger):
            mLogger(logger) {
        }

        void addComponent(EngineComponent& c, int pos) {
            mComponents[pos] = c;
            c.setEngine(this);
        }

        void log(const std::string& message) {
            mLogger.write(message);
        }
}

class EngineComponent {
    private:
        Engine* mEngine;
    protected:
        EngineComponent() {}
    public:
        void setEngine(Engine* engine) {
            mEngine = engine;
        }

        void log(const std::string& message) {
            if (mEngine != NULL) {
                mEngine->log(message);
            }
        }
}

class Window : public EngineComponent {
    // add implementation
}

class D3d11Renderer : public EngineComponent {
    // add implementation
}

class Logger {
    protected:
        Logger() {}
}

class FileLogger : public Logger {
    // add implementation
}

Hope it helps.

Henrique Barcelos
  • 7,670
  • 1
  • 41
  • 66