Solution: Singleton (Flexible And Strict)

Main Program

#include "social-insurance-flexible-strict.h"

// only there to deny compiability below
// #include "social-insurance-svs-strict.h"
// #include "social-insurance-oegk-strict.h"

#include <iostream>
#include <string>


int main()
{
    std::string id("1037190666");

    SocialInsurance::instance().charge(id, 1254.60);
    SocialInsurance::instance().charge(id, 231.34);

    std::cout << id << " owes \"" << SocialInsurance::instance().name() << "\" " << SocialInsurance::instance().debt(id) << " Euros" << std::endl;

    // MUST NOT COMPILE
    // ================

    // explicit instantiation (neither iface nor implementations)
    // ----------------------------------------------------------

    // SocialInsurance iface_instance("Another Insurance");
    // SVS svs_instance;
    // OEGK oegk_instance;

    // copy initialization
    // -------------------

    // SocialInsurance another_instance = SocialInsurance::instance();

    // copy assignment
    // ---------------

    // another_instance = SocialInsurance::instance();

    // and dynamic_cast?
    // -----------------

    // STOP HERE!!!

    return 0;
}

SocialInsurance Interface

#pragma once

#include <memory>


class SocialInsurance
{
public:
    const std::string& name() const { return _name; }

    virtual void charge(const std::string& id, double euros) = 0;
    virtual double debt(const std::string& id) const = 0;

private:
    std::string _name;

public:
    static SocialInsurance& instance();

protected:
    SocialInsurance(const std::string& name) : _name(name) {}

private:
    static std::unique_ptr<SocialInsurance> _instance;
};
#include "social-insurance-flexible-strict.h"

#include "social-insurance-svs-strict.h"
#include "social-insurance-oegk-strict.h"

#include <stdexcept>
#include <cstdlib>


std::unique_ptr<SocialInsurance> SocialInsurance::_instance;

SocialInsurance& SocialInsurance::instance()
{
    if (_instance == nullptr) {
        char* socinsur = std::getenv("SOCINSUR");
        if (socinsur == nullptr)
            throw std::runtime_error("Environment variable \"SOCINSUR\" is not set");
    
        std::string ssocinsur = socinsur;
        if (ssocinsur == "SVS")
            _instance = std::unique_ptr<SocialInsurance>(new SVS);
        else if (ssocinsur == "OEGK")
            _instance = std::unique_ptr<SocialInsurance>(new OEGK);
        else 
            throw std::runtime_error("Environment variable \"SOCINSUR\" has invalid value");
    }

    return *_instance;
}

Two Concrete Implementations

OEGK

#pragma once

#include "social-insurance-flexible-strict.h"

#include <iostream>
#include <map>


class OEGK : public SocialInsurance
{
public:
    virtual void charge(const std::string& id, double euros);
    virtual double debt(const std::string& id) const;

private:
    std::map<std::string, double> _database;

private:
    OEGK() : SocialInsurance("OEGK") {}
    friend class SocialInsurance;
};
#include "social-insurance-oegk-strict.h"


void OEGK::charge(const std::string& id, double euros)
{
    _database[id] += euros;
}

double OEGK::debt(const std::string& id) const
{
    auto found = _database.find(id);
    if (found == _database.end())
        throw std::runtime_error("not found");
    return found->second;
}

SVS

#pragma once

#include "social-insurance-flexible-strict.h"

#include <iostream>
#include <map>


class SVS : public SocialInsurance
{
public:
    virtual void charge(const std::string& id, double euros);
    virtual double debt(const std::string& id) const;

private:
    std::map<std::string, double> _database;

private:
    SVS() : SocialInsurance("SVS") {}
    friend class SocialInsurance;
};
#include "social-insurance-svs-strict.h"


void SVS::charge(const std::string& id, double euros)
{
    _database[id] += euros * (110.0L / 100);
}

double SVS::debt(const std::string& id) const
{
    auto found = _database.find(id);
    if (found == _database.end())
        throw std::runtime_error("not found");
    return found->second;
}