C++ 基类和派生类之间的调试器指针地址不同
给定,类B是基类,类D是从B派生的。 使用VS调试器-如果您有一个指向类D实例的指针-根据我们的定义,它也是指向类B的指针,因此您可以将其强制转换-这些指针显示为略有不同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,无论您是否正在铸造它。您没有创建新对象。地址将是相同的,位置上的对象已更改,位置仍然相同 想象一下,在你现在的地址建造
# 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写道,事实并非如此!它取决于继承和继承树中虚拟方法的存在。