C++ 基类和派生类之间的调试器指针地址不同

C++ 基类和派生类之间的调试器指针地址不同,c++,debugging,pointers,C++,Debugging,Pointers,给定,类B是基类,类D是从B派生的。 使用VS调试器-如果您有一个指向类D实例的指针-根据我们的定义,它也是指向类B的指针,因此您可以将其强制转换-这些指针显示为略有不同 # pseudo-code: B *pB = new D(); D *pD = (D*) pB; # why is: pb != pD 这个概念称为别名。 D pD=(D)pB; 在这里,您将pd分配给pb,无论您是否正在铸造它。您没有创建新对象。地址将是相同的,位置上的对象已更改,位置仍然相同 想象一下,在你现在的地址建造

给定,类B是基类,类D是从B派生的。 使用VS调试器-如果您有一个指向类D实例的指针-根据我们的定义,它也是指向类B的指针,因此您可以将其强制转换-这些指针显示为略有不同

# pseudo-code:
B *pB = new D();
D *pD = (D*) pB;
# why is: pb != pD

这个概念称为别名。 D pD=(D)pB; 在这里,您将pd分配给pb,无论您是否正在铸造它。您没有创建新对象。地址将是相同的,位置上的对象已更改,位置仍然相同

想象一下,在你现在的地址建造一个新家,你的地址仍然保持不变。
因此,如果比较这两个指针,它们将指向相同的地址。

这个概念称为别名。 D pD=(D)pB; 在这里,您将pd分配给pb,无论您是否正在铸造它。您没有创建新对象。地址将是相同的,位置上的对象已更改,位置仍然相同

想象一下,在你现在的地址建造一个新家,你的地址仍然保持不变。
因此,如果比较这两个指针,它们将指向同一个地址。

这不是标准要求。在基类指针和派生类指针之间来回转换时,仅需要获得相同的值:

B *pB = new D();
D *pD = (D*) pB;
B *pB2 = (B*) pD;
// pB2 == pB is guaranteed per C++ standard
// but nothing is required between pB and pD

一旦涉及到虚拟方法及其关联的vTable,实现通常会对派生类指针和基类指针使用不同的指针地址。

这不是标准要求。在基类指针和派生类指针之间来回转换时,仅需要获得相同的值:

B *pB = new D();
D *pD = (D*) pB;
B *pB2 = (B*) pD;
// pB2 == pB is guaranteed per C++ standard
// but nothing is required between pB and pD

一旦涉及到虚拟方法及其关联的vTable,实现通常会对派生类指针和基类指针使用不同的指针地址。

因为标准没有规定它们应该相同


其主要动机显然是多重继承。一个类可以从多个基类派生,因此显然不能强制派生子对象的开头与基类的开头相同,因为可能有多个基类。

因为标准没有规定它们应该相同


其主要动机显然是多重继承。一个类可以从多个基类派生,因此显然不能强制派生子对象的开头与基类的开头相同,因为可能有多个基类。

如果
D:[A,]B[,C]
需要使用
静态转换
,但不能
重新解释转换
。如果
B
D
D
中没有第一个基址,则
B
没有-
pD
将是!=
pB
所以,如果执行
(void*)pB==(void*)pD
比较(二进制指针比较),结果将是
TRUE
,但当比较
pB==pD
时,编译器首先将
pD
转换为
B*
。同样,如果
B
不是
D
D
的第一个基具有虚拟函数,而
B
没有,则结果将不同。因此,您可以在派生类中扩展vtable,而无需获得第二个vtable,但是,如果从多个基继承,则可以获得两个vtable。在继承链的中间添加一个VTABLE也会产生这样的效果。@ MatsPetersson——您可以在派生类中扩展VTABLE——仅当<代码> B <代码>也有VTABLE。但是如果
B
根本没有vatable,并且
D
拥有它-已经
B
将不会放在
D
的开头,RbMm:是的,正是我想说的。如果
D:[A,]B[,C]
需要使用
静态转换
但不
重新解释转换
。如果
B
D
D
中没有第一个基址,则
B
没有-
pD
将是!=
pB
所以,如果执行
(void*)pB==(void*)pD
比较(二进制指针比较),结果将是
TRUE
,但当比较
pB==pD
时,编译器首先将
pD
转换为
B*
。同样,如果
B
不是
D
D
的第一个基具有虚拟函数,而
B
没有,则结果将不同。因此,您可以在派生类中扩展vtable,而无需获得第二个vtable,但是,如果从多个基继承,则可以获得两个vtable。在继承链的中间添加一个VTABLE也会产生这样的效果。@ MatsPetersson——您可以在派生类中扩展VTABLE——仅当<代码> B <代码>也有VTABLE。但是如果
B
根本没有vatable,而
D
拥有它-已经
B
将不会放在
D
的开头。RbMm:是的,正是我想说的。“地址会是一样的”?OP写道,事实并非如此!这取决于继承和继承树中虚拟方法的存在。“地址将是相同的”?OP写道,事实并非如此!它取决于继承和继承树中虚拟方法的存在。