jeudi 29 juin 2017

C++ QueryInterface implementation using std::shared_ptr<>

I'm looking to write a small bit of C++11 re-usable code to provide similar functionality seen in COM/ATL's IUnknown. Specifically, I'm interested in the QueryInterface() functionality.

A have a few requirements in mind:

  1. Do not rely on RTTI. This rules out dynamic_cast<> (this is not out of personal choice!)
  2. Remove possible coding mistakes by making use of std::shared_ptr<> instead of raw pointers. Shared ptr also provides useful in-built functionality like custom deleters.
  3. Use enum ids to refer to interfaces.
  4. Cross platform is a must.

Some code provided by Alexandre in another SO question has given me some ideas. Nonetheless, what I am keen to try achieve is return a std::shared_ptr object from the query interface method.

I have started to write some code (see below) to demonstrate what I'm trying to achieve. I appreciate that it is not complete.

Trying to flesh this out, I quick ran into all sorts of problems related to type-casting. The code soon felt 'hackish'.

#include <iostream>
#include <memory>
#include <map>

//////////////////////////////////////////////////////////////////////
enum iid
{
    IID_ANONYMOUS       = 0,
    IID_FOO             = 1,
    IID_BAR             = 2,
};

//////////////////////////////////////////////////////////////////////
class abstract_anonymous
{
public:

    virtual ~abstract_anonymous() {}

    // Return 0 if succesful.
    template <class INTERFACE>
    bool query_interface(const iid id,
                         std::shared_ptr<INTERFACE> &inout_apObj)
    {
        // Magic here.
    }

protected:

    virtual std::map<iid, zzzzzzzzzz >  &interfaces_map() const = 0;
};

//////////////////////////////////////////////////////////////////////
class anonymous_base_impl // : public std::enable_shared_from_this<abstract_anonymous>
{
public:

    anonymous_base_impl()
    {
        add_interface(IID_ANONYMOUS, xxxxxxxxxxxx );
    }

    ~anonymous_base_impl() = default;



protected:

    void add_interface(const iid id, yyyyyyyyyyy )
    {
        m_mapInterfacs.emplace({id, yyyyyyyyyyy});
    }

    std::map<iid, zzzzzzzzzz >  &interfaces_map() const override
    {
        return m_mapInterfacs;
    };

private:

    std::map<iid, zzzzzzzzzz >     m_mapInterfacs;
};

Any tips/suggestion would be much appreciated.

Aucun commentaire:

Enregistrer un commentaire