限制C ++中虚拟基类的对象共享

时间:2015-04-25 09:54:10

标签: c++ inheritance multiple-inheritance modeling virtual-inheritance

我了解C ++中的物理和虚拟继承。但是,我想知道这个模型是否可以通过任何设计模式或技巧以某种方式实现。

E和F类以及它们的基础不应该被修改。想象一下它们来自一个外部库。

E和F以下的所有内容都是开放的。引入中间帮助类,非成员函数,模板......可以实现这一切的所有内容:

           BaseClass
           /       \
          /         \
         A           A
        / \         / \
       /   \       /   \
      B     C     B     D
       \   /       \   /
        \ /         \ /
         E           F
          \         /
           \       /
            \     /
           FinalClass

请注意,E和F不得共享A. FinalClass确实应包含2 A. 我的问题是,E或F的创建需要B,C和D虚拟地继承A ..但是,如果A是虚基类,那么编译器只会在FinalClass中创建一个A对象而不是两个不同的的。

所以,我想很多人会在这里推荐构图而不是继承。然而,组合模式在这里有一个" - 关系,而不是"是一个" - 关系。 在解释中,我希望FinalClass真正表现得像E或F,包括能够将它转换为那些类。

1 个答案:

答案 0 :(得分:2)

这种布局在C ++中是不可行的,即使有额外的帮助类也是如此。

B继承自A,并且您希望在一方与C共享A继承而在另一方与D共享A,这要求B,C和D实际上从A继承。但是A将被共享在你的钻石的两个分支。

替代

有哪些替代品?

  • 如果您设法打破钻石左右分支之间的A分享,您也会打破共同基础的共享。

  • 如果您引入了一些中间类A1,A2来实现分支机构中的左右分享,那么您必须坚持这样一个事实:B必须继承该分支或者另一个

  • 唯一的出路可能是为B.提供重复的课程。

最后一个解决方案并不能满足您的要求,但看起来如下:

struct Base { int x; };
struct A : public virtual Base { int a; };
struct AC : public A{};  // synonym 
struct B : public virtual A { int b; };
struct BC : public virtual AC { int b;  }; // !! clone !! 
struct C : public virtual AC { int c; };
struct D : public virtual A { int d; };
struct E : public BC, C { int e; };
struct F : public B, D { int f; };
struct Final : public E, F { };

在这里访问成员:

Final f;
f.x = 2;    // unambiguous:  there's onely one of it 
f.f = 1; 
f.e = 2; 
f.d = 3; 
f.c = 4; 
//f.b = 5;   // ambiguous:  there are two of it 
f.E::b = 5;  // successful desambiguation
f.F::b = 6;  // successfuldesambiguation
//f.a = 7;   // ambiguous:  there are two of it
f.E::a = 7;  // successful desambiguation
f.F::a = 8;  // successful desambiguation

回到你的问题陈述:你说你不能在E和F之上进行干预。在这种情况下,你的选择非常有限:

  • 你公开继承
  • 您通过某些中间类私下继承

但是在共享方面的效果是相同的,因为下面的代码示例(在上面的代码的顶部):

class FI : private F  // make F private
{ public: 
    void set_xa(int u, int v) { x = u; a= v; }
    void show_xa() { cout << "x:" << x << " a:" << a << endl; }
};
class EI : private E  // make E private
{
public:
    void set_xa(int u, int v) { x = u; a = v; }
    void show_xa() { cout << "x:" << x << " a:" << a << endl; }
};

struct Final3 : public EI, public FI { }; 

Final3 h;
h.EI::set_xa(3, 4);
h.FI::set_xa(5, 6);
h.EI::show_xa(); 
h.FI::show_xa();
// the shared virtually inherited memebers are still shared !

结论:

通过继承,你完全受到E和F以上设计的约束,你不能被影响。

所以第一个问题是:

  • 毕竟你不能改变这个设计(即克隆一个B)?
  • 在两个分支之间进行A剪切是不可接受的(毕竟可能有正确的理由)?

如果您对这两个问题的回答均为“否”,则您必须进行合成,并实施一种 proxy design pattern ,其中您的撰写对象是您的代理两个组成部分