#include<stdio.h>
class A { public: int a;};
class B: public A {
int c;
int d;
};
int main() {
A* pA = new B[10];
B* pB = new B[10];
printf("\n%d", pA->a);
pA++;
printf("\n%d", pA->a); // prints junk value
printf("\n\n%d", pB->a);
pB++;
printf("\n%d", pB->a);
return 0;
}
第二个printf
打印垃圾值。
它应该指出它指向B
类型的对象并按sizof(B)
递增。
为什么不会发生这种情况?
答案 0 :(得分:19)
不,不应该。声明的pA
类型为A*
,因此它增加sizeof(A)
,使其指向数组中第一个B的中间位置。
答案 1 :(得分:11)
它之所以脆弱,是因为你踩着它所做的一切,试图保证你的安全。除非你有足够的经验知道为什么会出现这些问题,以及如何避免这些问题,你应该:
printf
存在。请改用std::cout
。 new
存在。请改用std::vector
。您可能还应该阅读C ++常见问题解答,并密切关注那些说明效果的部分:“即使X是Y,X的数组也不是Y的数组。”
编辑:至于为什么你会看到你的行为,这很简单:指针算术是根据静态类型而不是动态类型定义的。这意味着它完全基于您为指针定义的指针类型,而不是它指向的内容。如果你说它指向一个A,但是然后将它指向一个B,算术仍然会像你所说的那样指向一个A。
答案 2 :(得分:7)
它只能在运行时知道。想象一下它有点变化
A* a;
if(runtimevalue)
a = new A[10];
else
a = new B[10];
但那不会发生。 C ++强调速度,但这基本上使它成为一种确保操作安全的语言。 Java,C#等已经解决了这个问题。
内核和设备驱动程序开发人员不需要聪明的语言运行时。他们只是想让事情快速发展。
查看Common undefined behavior in C++问题,了解需要“修复”的所有内容。它不再是C ++了!
答案 3 :(得分:3)
指针a
指向具有静态类型 A
和动态类型 B
的对象。 C ++中的指针算法适用于静态类型。因此,从指针算术的角度来看,a
指向A
类型的对象。
答案 4 :(得分:1)
您正在增加变量a
,它是A对象的本地声明指针。这与说a=a+sizeof(A)
一样。
由于sizeof(B)&gt; sizeof(A),你最终指向第一个对象的中间。当C ++然后添加适当的偏移量时,它将最终读取第一个B对象的c
字段。这恰好是整体记忆,包含“垃圾”。
答案 5 :(得分:1)
对象没有记录它们是什么或有多大,它只是分配了内存。编译器知道如何处理指针内存中对象的唯一方法是查看指针类型。因此,基于指针A *,它将仅假设一个sizeof(A)的对象。
答案 6 :(得分:1)
由于与C数组兼容的原因,降级为指针。 B[10]
的类型可能会降级为B*
,继承意味着将B
指针指定给类型为A*
的变量是有效的。
然后递增此指针的值,将A
的大小添加到其地址。
但是,如果指针未指向指针类型的元素数组,则假设递增指针是有效的操作是不正确的。
如果您尝试将C ++的各个部分组合在一起,那么它的行为就像C一样具有更强类型的OO特性,那么在C部分中更宽松的输入会破坏C ++部分中更强的类型。最好将它们分开,或者至少记录预期的行为。