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.
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);
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.
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
};
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.