Avoid Enumerations as C ++ OOP Interface Identifiers

I am working on a plugin platform using dynamically loaded shared libraries, which is based on the Eclipse (and probally other) extension model. All plugins have similar properties (name, identifier, version, etc.), and each plugin can theoretically satisfy any extension point. The actual processing of the plugin (i.e. Dll) is controlled by another library, and all I do is manage the collection of interfaces for the application.

I started by using enum PluginTypeto distinguish between different interfaces, but I quickly realized that using template functions made the code much cleaner and left grunt working up to the compiler, instead of forcing me to use a lot switch {...}.

The only problem is where I need to specify as functionality for class members. The most obvious example is the default plugin, which provides a specific interface. The class Settingshandles all settings, including the default plugin for the interface.

ie Skin newSkin = settings.GetDefault<ISkin>();

How to save the default ISkinin the container without resorting to any other means of identifying the interface?

As I mentioned above, I am currently using a member std::map<PluginType, IPlugin> Settings::defaultsto achieve this goal (where IPluginis the abstract base class from which all plugins are derived. Then I can dynamic_caston the desired interface, but it really smells like a bad design for me and does more harm. than i think.

will welcome any advice

edit:

typedef boost::shared_ptr<ISkin> Skin;
typedef boost::shared_ptr<IPlugin> Plugin;
enum PluginType
{
  skin,
  ...,
  ...
}

class Settings
{
public:
  void SetDefault(const PluginType type, boost::shared_ptr<IPlugin> plugin) {
    m_default[type] = plugin;
  }
  boost::shared_ptr<IPlugin> GetDefault(const PluginType type) {
    return m_default[type];
  }
private:
  std::map<PluginType, boost::shared_ptr<IPlugin> m_default;
};

SkinManager::Initialize()
{
  Plugin thedefault = g_settings.GetDefault(skinplugin);
  Skin defaultskin = boost::dynamic_pointer_cast<ISkin>(theskin);
  defaultskin->Initialize();
}

getdefault : . .

template<>
Skin Settings::GetDefault<ISkin>()
{
  return boost::dynamic_pointer_cast<ISkin>(m_default(skin));
}
+3
4

? .

? , .

:

class IPluginId
{
public:
  virtual IPluginId* clone() const = 0;
  virtual ~IPluginId();

  bool operator<(const IPluginId& rhs) const { return mId < rhs.mId; }
  bool operator==(const IPluginId& rhs) const { return mId == rhs.mId; }

protected:
  static size_t IdCount = 0;
  IPluginId(size_t id): mId(id) {}
private:
  size_t mId;
};

template <class Plugin>
class PluginId
{
public:
  PluginId(): IPluginId(GetId()) {}
  IPluginId* clone() const { return new PluginId(*this); }
private:
  static size_t GetId() { static size_t MId = ++IdCount; return MId; }
};

, , :

// skin.h

class ISkin;

struct SkinId: PluginId<ISkin> {}; // Types can be forward declared
                                   // Typedef cannot

class ISkin: public IPlugin { /**/ };

:

class Settings
{
public:
  template <class Plugin>
  void SetDefault(boost::shared_ptr<Plugin> p);

  template <class Plugin>
  boost::shared_ptr<Plugin> GetDefault(const PluginId<Plugin>& id);

private:
  boost::shared_ptr<IPlugin> GetDefault(const IPluginId& id);
};

- . , , , static_cast:)

, downcasting , down_cast GetDefault, .

( " " ):

class Settings
{
public:
  template <class Plugin>
  void SetDefault(const boost::shared_ptr<Plugin>& p)
  {
    mPlugins[typeid(Plugin).name()] = p;
  }

  template <class Plugin>
  boost::shared_ptr<Plugin> GetDefault() const
  {
    plugins_type::const_iterator it = mPlugins.find(typeid(Plugin).name());
    if (it == mPlugins.end()) return boost::shared_ptr<Plugin>();

    return shared_static_cast<Plugin>(it->second);
  }

private:
  typedef std::map<std::string, std::shared_ptr<IPlugin> > plugins_type;
  plugins_type mPlugins;
};

, , - , IPlugin, MySkin, , ISkin, typeid(T).name() .

0

boost:: variant ( ):

tyepdef boost::variant<
boost::shared_ptr<ISkin>,
boost::shared_ptr<IPluginType2>,
boost::shared_ptr<IPluginType3>,
etc...> default_t;
std::deque<default_t> defaults;

:

template <class T>
boost::shared_ptr<T> GetDefault() {
    for(std::deque<default_t>::iterator it = defaults.begin(), endIt = defaults.end();
        it != endIt;
        ++it) {
       boost::shared_ptr<T>* result = boost::get< boost::shared_ptr<T> >(*it);
       if( result ) {
           return *result;
       }
    }
    return boost::shared_ptr<T>(0);
}
+1

, Visitor-Pattern, . , -. Factory. , . , .

0

, - .

class Settings
{
    public:
        // ...
        template <class T>
        boost::shared_ptr<T> GetDefault()
        {
            // do something to convert T to an object (1)
            return m_default[T_as_an_obj];
        }
        // ....
};

SkinManager::Initialize()
{
    boost::shared_ptr<ISkin> defaultskin = g_settings.GetDefault<ISkin>();
    defaultskin->Initialize();
}        

Line (1) is the part that I think I saw before, but I don’t know how to do it myself. Also note that the current implementation returns a null pointer if you pass in a type that the Settings class has not yet seen. You will have to explain it somehow.

0
source

Source: https://habr.com/ru/post/1738490/


All Articles