c++ - 指向成员问题的指针

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

$4.11/2 个州 -

An rvalue of type “pointer to member of B of type cv T,” where B is a class type, can be converted to an rvalue of type “pointer to member of D of type cv T,” where D is a derived class (clause 10) of B. If B is an inaccessible (clause 11), ambiguous (10.2) or virtual (10.1) base class of D, a program that necessitates this conversion is ill-formed.

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

最佳答案

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

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 的指针”,您只需要一个指向 A 的整数偏移量子对象位于 B (第一个 A 子对象)。

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

因为编译器知道 B 在哪里和 C相对于 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;   | <--+
+-------------+

虚拟基类通常通过 B 来实现和 C (实际上派生自 A )包含指向单个 A 的指针子作业。指向 A 的指针子对象是必需的,因为 A 的位置相对于 BC不是常数。

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

关于c++ - 指向成员问题的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3501770/

相关文章:

c++ - 如何在不重载纯虚函数的情况下将抽象类转换为普通类?

c++ - 类派生形式结构上的虚函数

Java - 基类中的 Super.toString() 方法?

Powershell 从重写函数调用基类函数

c++ - LNK1120 和 LNK2019 错误

c++ - 如何在 Linux 上执行适用于 x86、arm、GCC 和 icc 的原子操作?

c++ - 如何调试 gRPC 服务器崩溃而不出现任何错误?

c++ - 调用 glDrawElements 导致访问冲突

c++ - 如果我将一个基类的析构函数从非虚拟更改为虚拟,会发生什么?

c# - 调用 this() 构造函数和不同的 base() 构造函数