为什么C ++会以这种方式运行?

时间:2010-05-19 18:35:06

标签: c++ arrays oop object

#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)递增。

为什么不会发生这种情况?

7 个答案:

答案 0 :(得分:19)

不,不应该。声明的pA类型为A*,因此它增加sizeof(A),使其指向数组中第一个B的中间位置。

答案 1 :(得分:11)

它之所以脆弱,是因为你踩着它所做的一切,试图保证你的安全。除非你有足够的经验知道为什么会出现这些问题,以及如何避免这些问题,你应该:

  1. 忘记printf存在。请改用std::cout
  2. 忘记new存在。请改用std::vector
  3. 您可能还应该阅读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 ++部分中更强的类型。最好将它们分开,或者至少记录预期的行为。