我的接口层次结构如下:
class A
{
public:
void foo() = 0;
};
class B: public A
{
public:
void testB() = 0;
};
class C: public A
{
public:
void testC() = 0;
};
现在,我想通过相同的层次结构来实现这些接口,即 Base class AImpl
,BImpl
但CImpl
我不确定如何从它们对应的接口派生它们。
请帮忙。提前致谢。
您可以使用单独的模板实现每个单独的接口,然后链接模板以构建派生对象,就像从构建块中一样。古老的 ATL 库也使用此方法来实现 COM 接口(对于我们这些足够老的人来说)。
请注意,您不需要虚拟继承。
我稍微修改了您的示例以获得更复杂的推导C -> B -> A
,以显示此方法如何轻松扩展:
#include <stdio.h>
// Interfaces
struct A
{
virtual void foo() = 0;
};
struct B : A
{
virtual void testB() = 0;
};
struct C : B
{
virtual void testC() = 0;
};
// Implementations
template<class I>
struct AImpl : I
{
void foo() { printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class I>
struct BImpl : I
{
void testB() { printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class I>
struct CImpl : I
{
void testC() { printf("%s\n", __PRETTY_FUNCTION__); }
};
// Usage
int main() {
// Compose derived objects from templates as from building blocks.
AImpl<A> a;
BImpl<AImpl<B> > b;
CImpl<BImpl<AImpl<C> > > c;
a.foo();
b.foo();
b.testB();
c.foo();
c.testB();
c.testC();
}
输出:
void AImpl<I>::foo() [with I = A]
void AImpl<I>::foo() [with I = B]
void BImpl<I>::testB() [with I = AImpl<B>]
void AImpl<I>::foo() [with I = C]
void BImpl<I>::testB() [with I = AImpl<C>]
void CImpl<I>::testC() [with I = BImpl<AImpl<C> >]
虽然在建议多重继承之前我通常会三思而后行。如果您的需求确实没有您说的那么复杂,那么只需虚拟地继承接口和实现即可。
class A
{
public:
void foo() = 0;
};
class B: virtual public A
{
public:
void testB() = 0;
};
class C: virtual public A
{
public:
void testC() = 0;
};
class AImpl : virtual public A
{
...
}
class BImpl : virtual public B, virtual public AImpl
{
...
}
虚拟继承将确保和A
之间仅共享一个子对象。所以你应该清楚。但是,对象大小会增加。因此,如果这是一个问题,请重新考虑您的设计。B
AImpl
我认为您要问的是,如何创建反映我的“交互”类层次结构的第二个实现类层次结构。您希望这样做以减少接口和实现之间的耦合。您的问题是您认为您的实现类应该扩展您的接口类,但也应该扩展 impl 类中的“自然”继承层次结构,如
AImpl
^ ^
| |
BImpl CImpl
我建议您查看描述此模式的 GoF(四人组)桥模式。实际上,书中的例子比维基百科上的要好,但似乎在网上找不到。这是一个粗略的(ascii)UML:
Window <>imp----------------------------> WindowImpl
^ ^ ^ ^
| | | |
| TransientWindow | PMWindowImp
IconWindow XWindowImp
在上面的示例中,您有一个引用实现的Window
类。#imp
因此,您的IconWindow
实现将具有#imp
引用,例如XWindowIconWindow
执行实际工作,但客户端只会通过IconWindow
实例引用它。这减少了您的重新编译开销。
需要说明的要点是:
我会留给您将其翻译为您的问题,但如果您有任何问题,请发表评论。
做
class BImpl : public B {
// code ...
}
但在 B 中,将函数声明为虚拟函数,因此编译器将强制您在 BImpl 中实现它们