3

I have two classes with same interface methods:

struct ImplGenerated {
    int foo(int x, int y);
    void bar(double x);
    ....
};

struct ImplCustom {
    int foo(int x, int y);
    void bar(double x);
    .....
};

And class Wrapper:

struct Wrapper {
    Wrapper(ImplGenerated * i): m_generated(i), m_custom(0) {}
    Wrapper(ImplCustom * i): m_generated(0), m_custom(i) {}
    int foo(int x, int y);
    void bar(double x);
    ....
private:
    ??? getImpl();
    ImplGenerated * m_generated;
    ImplCustom * m_custom;
};

int Wrapper::foo(int x, int y) {
    return getImpl()->foo(x, y);
}
void Wrapper::bar(double x) {
    getImpl()->bar(x);
}

Is it possible to write some C++ construction (class or any other, but not macros) instead getImpl() for resolving current implementation object and call corresponding method? like this:

???? getImpl() {
    return m_custom ? m_custom : m_generated;
}

Note: Only changes to ImplCustom could be applied (add base class or make template or something else), ImplGenerated is auto-generated by external project therefore couldn't be changed (add base class is impossible). Wrapper could not be template, because is interface class.

Update: It is impossible to derive ImplCustom from ImplGenerated.

  • Is it possible to derive `ImplCustom` from `ImplGenerated`? – SingerOfTheFall Oct 28 '15 at 13:45
  • You just cannot change a function's return type at runtime. The options are runtime polymorphism - base class pointer/reference and virtual functions, or compile time polymorhism - templates to generate more than one function. – Bo Persson Oct 28 '15 at 13:46

4 Answers4

4

The solution I see here is to create a wrapper

The goal of this solution is to generate an interface for your two unrelated classes.

Let's start by making a Base classe:

struct ImplInterface {
    virtual int foo(int x, int y) = 0;
    virtual void bar(double x) = 0;
    // ...
};

Now you can create wrapper for each Impl you got:

struct GeneratedWrapper : ImplInterface {
    virtual int foo(int x, int y) {
        _impl.foo(x, y);
    }

    virtual void bar(double x) {
        _impl.bar(x);
    }

private:
    ImplGenerated _impl;
};

struct CustomWrapper : ImplInterface {
    virtual int foo(int x, int y) {
        _impl.foo(x, y);
    }

    virtual void bar(double x) {
        _impl.bar(x);
    }

private:
    ImplCustom _impl;
};

Now you can use these wrapper like this:

ImplInterface* wrapper = new GeneratedWrapper(implGenerated);

This method could be much shorter using templates, let's make One wrapper for your new interface:

template<typename T>
struct EveryImplWrapper : ImplInterface {
    virtual int foo(int x, int y) {
        _impl.foo(x, y);
    }

    virtual void bar(double x) {
        _impl.bar(x);
    }

private:
    T _impl;
};

Now you can use it like this:

ImplInterface* = new EveryImplWrapper<ImplCustom>(implCustom);
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
2

If you can't modify the existing classes, you can still add a facade to provide post-hoc polymorphism. That is:

Wrapper could not be template, because is interface class

is only partly true. You can have a non-templated interface (ABC) and a templated concrete subclass.

// publically visible parts
struct ImplInterface {
    virtual ~ImplInterface() {}
    virtual int foo(int x, int y) = 0;
    virtual void bar(double x) = 0;
    ....
};

struct Wrapper {
    // ...
    ImplInterface *Wrapper::getImpl();
    // ... do you want to keep the same impl selection across calls?
    ImplInterface *m_impl;
};

// implementation details can be hidden in a cpp file

template <typename RealImpl>
struct ImplFacade: ImplInterface {
    RealImpl pimpl_;

    explicit ImplFacade(RealImpl *impl) : pimpl_(impl) {}

    int foo(int x, int y) override { return pimpl_->foo(x,y); }
    void bar(double x)    override { pimpl_->bar(x); }
};

ImplInterface *Wrapper::getImpl() {
    if (!m_impl) {
        if (m_custom)
            m_impl = new ImplFacade<ImplCustom>(m_custom);
        else
            m_impl = new ImplFacade<ImplGenerated>(m_generated);
    }
    return m_impl;
}

Ideally you should be using unique_ptr for the new member in real code.

Useless
  • 64,155
  • 6
  • 88
  • 132
  • It is ideal solution, but is very hard to realize in current project, with hundreds methods and interfaces – Evgeny Klyuzin Oct 28 '15 at 14:14
  • If you have hundreds of methods and interfaces, _nothing_ is going to be easy, unless you can find a way to generate the code. – Useless Oct 28 '15 at 15:09
2

If you can use the c++11 Standard you can use std::function to accomplish this:

struct Wrapper {
    Wrapper(ImplGenerated * i):
        foo(std::bind(&ImplGenerated::foo, i)),
        bar(std::bind(&ImplGenerated::bar, i)) {}

    Wrapper(ImplCustom * i):
        foo(std::bind(&ImplCustom ::foo, i)),
        bar(std::bind(&ImplCustom ::bar, i)) {}

    //Now the functions are member variables but it works the same way
    std::function<int(int x, int y)> foo;
    std::function<void(double x)> bar;
    ....

//If you don't Need to destruct the impl-objects then you don't even Need to store them
};
Thomas Sparber
  • 2,827
  • 2
  • 18
  • 34
  • This would imply a lot of dynamic allocation and a lot of indirection :( – Guillaume Racicot Oct 28 '15 at 14:17
  • @GuillaumeRacicot actually, `std::function` have a very good Performance. I also think that the won't be much dynamic allocation since it's just binding one member function. – Thomas Sparber Oct 28 '15 at 14:31
  • Thanks for your solution! Yes, I can use c++11 Standard. This decision imply to write a lot of code, but I would like to do the writing less code – Evgeny Klyuzin Oct 28 '15 at 14:34
  • 1
    @EvgenyKlyuzin You're welcome! Actually if you look closer you can see that you don't Need to write so much code because you don't Need to write the implementation of the functions... You just bind them in the constructor – Thomas Sparber Oct 28 '15 at 14:36
  • 1
    @Thomas Sparber Maybe! It would be interesting to see what are the performance of `std::function` vs virtual dispatch. – Guillaume Racicot Oct 28 '15 at 14:43
  • 1
    @GuillaumeRacicot Well you can see that :-) See here: http://stackoverflow.com/questions/14306497/performance-of-stdfunction-compared-to-raw-function-pointer-and-void-this – Thomas Sparber Oct 28 '15 at 14:47
  • @Thomas Sparber Thanks for link! – Guillaume Racicot Oct 28 '15 at 14:49
-1

I believe what you're wanting is to use inheritance / interface:

struct ImplInterface {
    virtual int foo(int x, int y) = 0;
    virtual void bar(double x) = 0;
    ....
};

struct ImplGenerated : public ImplInterface {
    virtual int foo(int x, int y);
    virtual void bar(double x);
    ....
};

struct ImplCustom : public ImplInterface {
    virtual int foo(int x, int y);
    virtual void bar(double x);
    .....
};

now your getImpl() will return a ImplInterface*

Or if you can't add a base class, then in your Wrapper class instead of getImpl() do this:

int foo(int x, int y)
{
    if (m_generated != nullptr)
    {
         return m_generated->foo(x,y);
    }
    else if (m_custom != nullptr)
    {
         return m_custom->foo(x, y);
    }
    throw "hey dude!";
}

I know it's a lot of work, but hey you've no base class to work with.

GreatAndPowerfulOz
  • 1,767
  • 13
  • 19