【问题标题】:Multiple Inheritance Class References多个继承类引用
【发布时间】:2012-06-08 06:37:16
【问题描述】:

假设我有一对基类:

class A
{};

class B
{
    virtual void foo(A* ref);
    virtual void foo2(A* ref);
};

还有一些派生类:

class C : virtual public A
{
   int data;
};

class D : public B
{
    virtual void foo(A* ref)
    {
        ((C*) (ref)).data = 5;
    }
};

class E : virtual public A
{
    int otherData;
};

class F : public B
{
    virtual void foo2(A* ref)
    {
        ((E*) (ref)).otherData = 6;
    }
};

最后,我们有一个类似的类,如下所示:

class G : public E, public C
{
};

主要功能如下:

int main()
{
   B* myD = new D();
   B* myF = new F();

   A* myA = new G();

   myD->foo(myA);
   myF->foo2(myA);

   return 0;
}

好吧,忽略这是一颗“可怕的钻石”这一显而易见的事实(由于virtual,“多重 As”问题已被避免),一般的想法是我希望我的所有对象都是 Gs , Ds 和 Fs,但存储为对 As 和 Bs 的引用。我希望能够使用 B(实际上总是 D 或 F)虚函数来修改 G 的值......但是,A 和 B 不知道它们的任何子类,因此不能使用声明他们。这意味着虚函数参数必须始终是指向 A 的指针。但是,D 希望它的输入始终是 C,而 F 希望它的输入始终是 E。虽然如果 G 是,这可能不是问题仅从一个父级继承,我们当前的 G 是从 2 个父级继承的;我不知道this 指针在这种情况的底层上下文中实际上是如何工作的……但是,我不认为这是一种可能的情况。

是否有人愿意阐明将指针转换为父/子类的机制,以及是否有任何方法可以实现这一点?

【问题讨论】:

  • 实际上,我在这里害怕的不是钻石,而是:1/ 使用未经检查的指针 => 请通过引用传递ref 2/ 使用 C-casts => 请使用适当的 C++ 强制转换(这里可能带有运行时检查)

标签: c++ class multiple-inheritance virtual-functions


【解决方案1】:

假设您已打开 RTTI,您很可能会这样做,您可以使用 dynamic_cast 尝试将基类指针向上转换为派生(或兄弟)类指针。引用的对象在运行时进行测试,看它是否是一个兼容的类,如果这不是一个有效的向上转换,它将返回 0,在这种情况下你可以测试它并进行分支。

http://en.wikipedia.org/wiki/Dynamic_cast

【讨论】:

    【解决方案2】:

    由于AG 的虚拟基,您不能将指向A 的指针静态转换为指向G 的指针。 virtual 的全部含义是“在运行时确定”,因此您拥有指针的A-子对象的性质只能在运行时知道。例如,在您的情况下考虑:

    A * p = new G, q = new C;
    

    现在pq 都指向一些 A-subobject,但是包含它们的最衍生对象的性质仅由实际最衍生的对象决定类型。因此,不可能有一个从A*G* 或从A*C* 的单一固定转换规则。

    执行强制转换的唯一方法是动态,即通过dynamic_cast<C*>(p) 等。

    (相比之下,在非虚拟继承中,总是知道子对象如何与其更多派生对象相关联,因此指针可以被静态转换。如果存在命名歧义的问题,如果您有多个重复的基础,但定位基础子对象没有问题。)

    【讨论】:

      【解决方案3】:

      正如 Kerrek 和 Andrew 所说,您应该使用 dynamic_cast。但是,如果 A 的子代是静态的,您可以使用不同的技巧,它可能比 dynamic_cast 更快(因为它不依赖于 RTTI,请参阅 this question 了解更多信息)。

      class C;
      class D;
      class E;
      class F;
      
      class A
      {
      public:
          virtual C * isC () { return 0; }
          virtual E * isE () { return 0; }
      };
      
      class C : virtual public A
      {
          friend class D;
          int data;
          C * isC () { return this; }
      };
      
      class E : virtual public A
      {
          friend class F;
          int otherData;
          E * isE () { return this; }
      };
      

      现在,DF 可以查询 A 以查看 isCisE 是否返回有效指针。

      【讨论】:

      • 这主要取决于 RTTI 是如何在内部实现的,但是,对于许多平台,您所描述的并不多于 - 不亚于 dynamic_cast 的实际实现方式(函数被隐式添加到并行对象层次结构中) .所以我不希望有任何特定的性能差异。当然,除非编译器的效率特别低下!
      • @EmilioGaravaglia:检查this,特别是VladV的回答。
      猜你喜欢
      • 2013-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多