Ximik
Ximik

Reputation: 2495

Best way to organize singleton with virtual methods

I'm working on simple framework written on C++. Now i have something like

app.cpp

#include "app.h"

namespace App
{

}

void App::init()
{

}

void App::timerEvent(int time)
{

}

But what if i don't want to listen to timerEvent in some cases? I still have to write empty method implementation.

My idea is to move from namespace to class App : public BaseApp with virtual void BaseApp::init() = 0 and virtual void BaseApp::timerEvent(int time) {} in BaseApp (similary to Qt QApplication). However App should be singleton then, but i don't see any way to specify it from BaseApp, so i have to write singleton code in App and all virtual idea makes no sense.

How should i design it?

P.S. I don't want to use listeners here. It seems like overkill for me.

P.P.S. I need singleton because i initialize app instance from main, but still want to access its methods from another classes.

Upvotes: 3

Views: 1969

Answers (1)

user2807083
user2807083

Reputation: 2972

You can emulate virtual functions inside your namespace with function pointer or std::function. Just make something like this:

#include "app.h"

namespace App
{
    std::function<void(int)> vtTimerEvent;
}

void App::timerEventImpl(int time)
{
    // default timerEvent implementation
}

void App::init(std::function<void(int)> timerEvent = &App::timerEventImpl)
{
    vtTimerEvent = timerEvent;
}

void App::timerEvent(int time)
{
   vtTimerEvent(time);
}

This is not very great design, but it does what you want.

UPDATE

Another approximation:

#include <memory>
#include <stdexcept>

// virtual base interface
class IInterface
{
public:
    virtual ~IInterface() = 0;
};

IInterface::~IInterface(){} // must have

// virtual App interface
class IApp :
    virtual public IInterface
{
public:
    virtual void init() = 0;
    virtual void timerEvent(int time) = 0;
};


// static App interface
class App
{
private:
    ~App(); // nobody can create an instance
public:
    static void init(const std::shared_ptr<IApp> &impl_p)
    {
        if (!impl)
        {
            impl = impl_p;
            impl->init();
        }
        else
        {
            throw std::runtime_error("Already initialized");
        }
    }

    static void timerEvent(int time)
    {
        impl->timerEvent(time);
    }
private:
    static std::shared_ptr<IApp> impl;
};

std::shared_ptr<IApp> App::impl;

// specific App implementation
class AppImplementation1 :
    public IApp
{
    //...
};


int main(int, char**)
{
    auto myImpl = std::make_shared<AppImplementation1>();
    App::init(myImpl);
    //...
    return 0;
}

Upvotes: 2

Related Questions