为什么两个指针值不同?

Why don't the two pointer values be the same?

本文关键字:指针 两个 为什么      更新时间:2023-10-16

引用有效C++,Scott Meyer,第3版,第27项

class Base { ... };
class Derived: public Base { ... };
Derived d;
Base *pb = &d; // implicitly convert Derived* ⇒ Base*

这里我们只是创建一个指向派生类的基类指针对象但有时,两个指针值将不相同如果是这种情况,则在运行时将偏移应用于Derived*指针,以获得正确的Base*指针值。

为什么两个指针值不一样?如果是因为子对象和父对象在内存中的布局,那么下转换以后如何工作?

使用多重继承时总是会发生这种情况。

class Base1 { int a; };
class Base2 { double b };
class Derived : public Base1, public Base2 { ... };
Derived d;
Base1* pb1 = &d;
Base2* pb2 = &d;

现在&d不可能同时等于pb1pb2,因为否则pb1将等于pb2,这是不可能的,因为两个不相关类型的不同非空对象必须占用不同的内存区域。因此,至少在一种情况下,必须应用非零偏移。

在大多数具有单一继承的实现中,偏移量为零,但标准并没有强制要求这样做。

事实上,一个典型的实现只需在派生对象的开头布置基本对象:

 ++-----++
 ||Base ||
 |+-----+|
 |Derived|
 +-------+

但当有多个基地时,一开始只能有一个基地:

 ++-----++
 ||Base1||
 |+-----+|
 ||Base2||
 |+-----+|
 |Derived|
 +-------+

下转换之所以有效,是因为偏移量是固定的,并且在编译时是已知的,所以在上转换或下转换时应用它没有问题。

一个例外是虚拟继承。对于虚拟基,偏移量在编译时是未知的。通常,派生对象包含一个指向其虚拟基的内部隐藏指针,因此上行可以工作。但是基不知道它的派生对象在哪里,所以向下转换不能工作,而且语言也不允许这样做。

当您有一个多态的继承树时,编译器要求每个对象以VMT(虚拟方法表)开头。如果基类是多态的,指针值就会匹配。但是如果你的基类是非多态的,而你的派生类是多态的,那么基类不会引入VMT,它是由树下的第一个多态类引入的。VMT将插入底座之前。现在指针值将不匹配。