在我的C ++项目中,我经常遇到以下情况:我有一个类A
,它有一个指向另一个类X
的接口的指针。
该类A
已扩展为处理X
的子类型。而这种情况又重演了。
请注意,在每个层中,接口都会更改(添加了新的对象方法,而其他一些方法会被重载),因此在A
的每个子类中,指向X
的指针都会转换为子类X
+----------+ +----------+
| | A has X | |
| A +-------------------> X |
+-----+----+ +-----+----+
| |
| |
| |
+-----+----+ +-----+----+
| | | |
| B +-------------------> Y |
+-----+----+ +-----+----+
| |
+-----+----+ +-----+----+
| | | |
| C +-------------------> Z |
+----------+ +----------+
我想知道是否有任何处理这种情况的模式,或者它本质上是一个糟糕的设计?
编辑,请考虑以下结构:
+----------+ +----------+ +----------+
| | | | A has X | |
| M <----------+ A +-------------------> X |
+-----+----+ +-----+----+ +-----+----+
| | |
| | |
| | |
+-----+----+ +-----+----+ +-----+----+
| | | | | |
| N <----------+ B +-------------------> Y |
+-----+----+ +-----+----+ +-----+----+
| | |
+-----+----+ +-----+----+ +-----+----+
| | | | | |
| L <----------+ C +-------------------> Z |
+----------+ +----------+ +----------+
这实际上是应用程序的外观。每个级别代表我们多层框架中的一个层。
答案 0 :(得分:1)
考虑这个实现:
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> {};
答案 1 :(得分:-2)
你在这里被称为&#34;钻石问题&#34; (参见Wikipedia)并且可以使用虚拟继承来解决(参见this article)。
class InterfaceA
{};
class TypeA: public virtual InterfaceA
{};
class InterfaceB: public virtual InterfaceA
{};
class TypeB: public TypeA, public InterfaceB
{};
不要使用reinterpret_cast从TypeB转换为InterfaceA(虚拟继承具有与直接继承不同的内存布局)