我有两个具有相同接口方法的类:
struct ImplGenerated {
int foo(int x, int y);
void bar(double x);
....
};
struct ImplCustom {
int foo(int x, int y);
void bar(double x);
.....
};
和课程包装:
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);
}
是否可以编写一些C ++构造(类或任何其他但不是宏)而不是 getImpl()来解析当前的实现对象并调用相应的方法? 像这样:
???? getImpl() {
return m_custom ? m_custom : m_generated;
}
注意: 只能应用对ImplCustom的更改(添加基类或制作模板或其他内容),ImplGenerated由外部项目自动生成,因此无法更改(添加基类是不可能的)。 包装器不能是模板,因为是接口类。
更新: 从ImplGenerated派生ImplCustom是不可能的。
答案 0 :(得分:4)
我在这里看到的解决方案是创建一个包装器
此解决方案的目标是为两个不相关的类生成一个接口。
让我们从制作Base classe开始:
struct ImplInterface {
virtual int foo(int x, int y) = 0;
virtual void bar(double x) = 0;
// ...
};
现在你可以为你得到的每个Impl创建包装器:
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;
};
现在您可以像这样使用这些包装器:
ImplInterface* wrapper = new GeneratedWrapper(implGenerated);
使用模板可以缩短这个方法,让我们为你的新界面制作一个包装器:
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;
};
现在您可以像这样使用它:
ImplInterface* = new EveryImplWrapper<ImplCustom>(implCustom);
答案 1 :(得分:2)
如果无法修改现有类,仍可以添加外观以提供事后多态。那就是:
Wrapper不能是模板,因为是接口类
只是部分正确。你可以有一个非模板化的接口(ABC)和一个模板化的具体子类。
// 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;
}
理想情况下,您应该在实际代码中使用unique_ptr
作为新成员。
答案 2 :(得分:2)
如果您可以使用c ++ 11 Standard,则可以使用std::function
来完成此操作:
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
};
答案 3 :(得分:-1)
我相信你想要的是使用继承/接口:
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);
.....
};
现在,您的getImpl()
将返回ImplInterface*
或者,如果您无法添加基类,则在Wrapper
班级而不是getImpl()
执行此操作:
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!";
}
我知道它做了很多工作,但嘿,你没有基础可以合作。