c++中的递归组合



在我的C++项目中,我经常遇到以下情况,其中我有一个类A,它有一个指向另一个类的接口X的指针。该类A被扩展为处理X的子类型。这种情况再次发生。

请注意,在每一层,接口都会发生变化(添加了新的对象方法,并重载了其他一些方法),因此在A的每个子类中,指向X的指针被转换为X 的子类

+----------+                   +----------+
|          |    A has X        |          |
|   A      +------------------->    X     |
+-----+----+                   +-----+----+
      |                              |
      |                              |
      |                              |
+-----+----+                   +-----+----+
|          |                   |          |
|    B     +------------------->     Y    |
+-----+----+                   +-----+----+
      |                              |
+-----+----+                   +-----+----+
|          |                   |          |
|   C      +------------------->    Z     |
+----------+                   +----------+

我想知道是否有任何模式可以处理这种情况,或者它本质上是一个糟糕的设计?

EDIT,考虑以下结构:

+----------+          +----------+                   +----------+
|          |          |          |    A has X        |          |
|    M     <----------+   A      +------------------->    X     |
+-----+----+          +-----+----+                   +-----+----+
      |                     |                              |
      |                     |                              |
      |                     |                              |
+-----+----+          +-----+----+                   +-----+----+
|          |          |          |                   |          |
|     N    <----------+    B     +------------------->     Y    |
+-----+----+          +-----+----+                   +-----+----+ 
      |                     |                              |
+-----+----+          +-----+----+                   +-----+----+
|          |          |          |                   |          |
|    L     <----------+   C      +------------------->    Z     |
+----------+          +----------+                   +----------+

这实际上就是应用程序的外观。每个级别代表我们多层框架中的一层。

考虑一下这个实现:

struct X {};    
struct Y: X {};
struct Z: X {};
class A
{
    // todo: add public interface
protected:
    std::unique_ptr<X> x_;
};
template<typename T>
class AImpl: public A
{
protected:
    T* get() { return dynamic_cast<T*>(x_.get()); }
};
class B: public AImpl<Y>
{
public:
    // todo: add public interface
    using AImpl<Y>::get; // implement rest of B in terms of this
};
class C: public AImpl<Z>
{
public:
    // todo: add public interface
    using AImpl<Z>::get; // implement rest of C in terms of this
};

编辑(因为C需要从B继承)

考虑将B和C定义如下:

template<typename T>
class BImpl: public AImpl<T>
{
public:
    // todo: add public interface
    using AImpl<T>::get; // implement rest of B in terms of this
};
// this is a new thing (see my explanation on this, below)
using B = BImpl<Y>;
class C: public BImpl<Z>
{
public:
    // todo: add public interface
    using AImpl<Z>::get; // implement rest of C in terms of this
};

但是,实现这样的B有一个问题:让类做不止一件事是糟糕的设计。在这种情况下,B必须既是基类(对于C)又是具体类型。

我创建了一个B实现类作为基础。然后,定义B可以是类型别名(我在上面使用的语句),也可以是具体的类型专门化:

class B: public BImpl<Y> {};

这里的问题被称为"钻石问题"(请参阅维基百科),它可以通过使用虚拟继承来解决(请参阅本文)。

class InterfaceA
{};
class TypeA: public virtual InterfaceA
{};
class InterfaceB: public virtual InterfaceA
{};
class TypeB: public TypeA, public InterfaceB
{};

不要使用interpret_cast进行强制转换,即从TypeB到InterfaceA(虚拟继承与直接继承具有不同的内存布局)

最新更新