指向成员问题的指针

时间:2010-08-17 11:15:00

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

$ 4.11 / 2州 -

  

“指向成员的指针”的右值   属于 cv B的{​​{1}},“其中T是一个类   type,可以转换为rvalue   键入“指向B类型成员的指针    cv D,“其中T是派生类   ({1}}的(第10条)。如果D是   难以接近(第11条),含糊不清   (10.2)或虚拟(10.1)基类   B,一个需要这个的程序   转换是不正确的。

我的问题是为什么我们限制B不是D的虚拟基类?

3 个答案:

答案 0 :(得分:5)

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

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 a对象中A的整数偏移量为零。因此,“int a类型A的指针”可能只是零的整数偏移量。

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

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

由于编译器知道CA相对于B的位置,编译器有足够的信息说明如何从C转发到AA

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

B

可能的内存布局:

C

虚拟基类通常通过让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; | <--+ +-------------+ (实际上派生自B)包含指向单个C子主题的指针来实现。指向A子对象的指针是必需的,因为A相对于AA的位置不是常量。

如果我们所拥有的只是“指向B类型C的指针”,我们将无法将其转换为“int a类型A的指针“},因为int aB子对象的位置可能会因B而异。 C没有指向AA的指针,因此我们根本没有足够的信息让转发效果正常。

答案 1 :(得分:1)

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

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

C ++背后的一般原则是尽可能避免运行时开销。在这种情况下,选择是在对相当常见的操作进行运行时检查,而不是禁止相当模糊的转换,并且似乎在这里应用了该主体。

答案 2 :(得分:0)

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