【问题标题】:Pointer to member question指向成员问题的指针
【发布时间】:2010-08-17 11:14:59
【问题描述】:

$4.11/2 个州 -

“指向成员的指针”类型的右值 B 类型 cv T,”其中B 是一个类 类型,可以转换为右值 键入“指向D 类型成员的指针 cv T,” 其中D 是派生类 B 的(第 10 条)。如果B 是 无法访问(第 11 条),模棱两可 (10.2) 或虚拟 (10.1) 基类 D,一个需要这个的程序 转换格式不正确。

我的问题是为什么我们限制@9​​87654330@ 不是D 的虚拟基类?

【问题讨论】:

    标签: c++ virtual base-class pointer-to-member


    【解决方案1】:

    考虑一个涉及非虚拟基类的情况:

    class A { int a; }
    class B : public A { int b; }
    class C : public A { int c; }
    class D : public B, public C { int d; }
    

    这是一个可能的内存布局:

    +-------------+
    | A: int a;   |
    +-------------+
    | B: int b;   |
    +-------------+
    | A: int a;   |
    +-------------+
    | C: int c;   |
    +-------------+
    | D: int d;   |
    +-------------+
    

    D 最终有两个 A 子对象,因为它继承自 BC 并且每个都有一个 A 子对象。

    指向成员变量的指针通常实现为距对象开头的整数偏移量。在这种情况下,int aA 对象中的整数偏移量为零。所以“指向int a 类型A 的指针”可能只是一个零整数偏移量。

    要将“指向int a 类型A”的指针转换为“指向int a 类型B”的指针,您只需要一个整数偏移量到位于B 中的A 子对象(第一个A 子对象)。

    要将“指向A 类型的int a 的指针”转换为“指向int a 类型的C 的指针”,您只需要到位于C 中的A 子对象的整数偏移量(第二个A 子对象)。

    由于编译器知道BC 相对于A 的位置,因此编译器有足够的信息来说明如何从A 向下转换为BC

    现在考虑一个涉及虚拟基类的情况:

    struct A { int a; }
    struct B : virtual public A { int b; }
    struct C : virtual public A { int c; }
    struct D : public B, public C { int d; }
    

    可能的内存布局:

    +-------------+
    | B: ptr to A | ---+
    |    int b;   |    |
    +-------------+    |
    | C: ptr to A | ---+
    |    int c;   |    |
    +-------------+    |
    | D: int d;   |    |
    +-------------+    |
    | A: int a;   | <--+
    +-------------+
    

    虚拟基类通常通过使BC(实际上派生自A)包含一个指向单个A 子对象的指针来实现。需要指向A 子对象的指针,因为A 相对于BC 的位置不是恒定的。

    如果我们只有一个“指向int a 类型为A 的指针”,我们将无法将其转换为“指向int a 类型B 的指针”,因为BC 子对象可以相对于 A 有所不同。 A 没有指向 BC 的反向指针,所以我们根本没有足够的信息让 downcast 工作。

    【讨论】:

      【解决方案2】:

      使用非虚拟继承,基类和派生类成员可以在内存中连续布局,基类在前,这样每个基类成员相对于对象的地址位于相同的位置对象是B 还是D。这使得将指向成员的指针B 转换为指向成员的指针D 变得容易;两者都可以表示为对象地址的偏移量。

      使用虚拟继承,必须通过派生对象中的指针(或等效项)访问基类成员,指示基类所在的位置。这将需要向指向成员的指针表示添加额外的信息以指示需要这种间接性,并且在使用 any 指向成员的指针时需要进行运行时检查。

      大部分 C++ 背后的一般原则是尽可能避免运行时开销。在这种情况下,选择是在对相当常见的操作进行运行时检查与不允许相当​​模糊的转换之间进行选择,似乎这里应用了该主体。

      【讨论】:

        【解决方案3】:

        非常有趣的问题。今天学到了新东西。这是我能找到的与该主题相关的内容: Casting member function pointers from derived class to virtual base class does not work

        【讨论】:

          猜你喜欢
          • 2018-03-24
          • 1970-01-01
          • 1970-01-01
          • 2013-05-02
          • 2010-10-01
          • 2016-07-30
          • 2023-03-12
          • 2021-12-03
          • 1970-01-01
          相关资源
          最近更新 更多