#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;
}
The second printf
prints a junk value.
第二个printf打印垃圾值。
It should figure that it is pointing to an object of type B
and increment by the sizof(B)
.
它应该指出它指向一个B类型的对象并通过sizof(B)递增。
Why does that not happen?
为什么不会发生这种情况?
7 个解决方案
#1
7
It can only know that at runtime. Imagine it slightly changed
它只能在运行时知道。想象一下它有点变化
A* a;
if(runtimevalue)
a = new A[10];
else
a = new B[10];
But that's not going to happen. C++ puts emphasize in speed, but this would basically make it into a language that ensures safety of operations. There is Java, C# and others that already solve this.
但那不会发生。 C ++强调速度,但这基本上使它成为一种确保操作安全的语言。有Java,C#等已经解决了这个问题。
Kernel and device driver developers don't want a clever language runtime. They just want to have things run fast.
内核和设备驱动程序开发人员不希望有一个聪明的语言运行时。他们只是想让事情快速发展。
Have a look at Common undefined behavior in C++ question for all the things that will need to get "fixed" along. It won't be C++ anymore!
在C ++问题中查看需要“修复”的所有内容的常见未定义行为。它不再是C ++了!
#2
19
No it shouldn't. The declared type of pA
is A*
, so it is incremented by sizeof(A)
, which leaves it pointing to the middle of the first B in the array.
不,不应该。声明的pA类型是A *,因此它增加sizeof(A),使其指向数组中第一个B的中间。
#3
11
The reason it's fragile is that you're side-stepping everything it does to try to keep you safe. Until you're sufficiently experienced to know why these problems are arising, and how to avoid them, you should:
它之所以脆弱,是因为你踩着它所做的一切,试着保证你的安全。除非你有足够的经验知道为什么会出现这些问题,以及如何避免这些问题,你应该:
- Forget that
printf
exists. Usestd::cout
instead. - Forget that
new
exists. Usestd::vector
instead.
忘记printf存在。请改用std :: cout。
忘记新的存在。请改用std :: vector。
You should probably also read the C++ FAQ, and pay close attention to the part that says something to the effect that: "Even if an X is a Y, an array of X is not an array of Y."
您可能还应该阅读C ++常见问题解答,并密切关注那些说明效果的部分:“即使X是Y,X的数组也不是Y的数组。”
Edit: As to why you're seeing the behavior you are, it's pretty simple: pointer arithmetic is defined in terms of the static type, not the dynamic type. That means it's based entirely on the type of pointee you defined for the pointer, NOT what it's pointing at. If you say it's pointing at an A, but then point it at a B, the arithmetic will still be done as if it was pointing at an A as you said it would.
编辑:至于为什么你会看到你的行为,这很简单:指针算术是根据静态类型而不是动态类型定义的。这意味着它完全基于您为指针定义的指针类型,而不是它指向的内容。如果你说它指向一个A,但是然后将它指向一个B,算术仍然会像你所说的那样指向一个A。
#4
3
Pointer a
points to an object that has static type A
and dynamic type B
. Pointer arithmetic in C++ works in terms of static type. So, from the point of view of pointer arithmetic, a
points to an object of type A
.
指针指向具有静态类型A和动态类型B的对象.C ++中的指针算法在静态类型方面起作用。因此,从指针算法的角度来看,指向A类型的对象。
#5
1
the objects have no record of what or how large they are, it's just allocated memory. The only way the compiler knows how to treat the object at the pointer memory, is by looking at the pointer type. So based on pointer A*, it will only assume an object of sizeof(A).
对象没有记录它们是什么或有多大,它只是分配了内存。编译器知道如何处理指针内存中对象的唯一方法是查看指针类型。因此,基于指针A *,它将仅假设sizeof(A)的对象。
#6
1
For reasons of compatibility with C arrays degrade to pointers. The type of B[10]
may degrade to B*
, and inheritance means that the assignment of a pointer to B
to a variable of type A*
is valid.
出于与C数组兼容的原因,降级为指针。 B [10]的类型可能降级为B *,继承意味着将指向B的指针分配给类型A *的变量是有效的。
You then increment the value of this pointer, which adds the size of A
to its address.
然后,您可以递增此指针的值,这会将A的大小添加到其地址。
However, your assumption that incrementing a pointer is a valid operation if the pointer is not pointing to an array of elements of the type of the pointer is not correct.
但是,如果指针未指向指针类型的元素数组,则假设递增指针是有效操作是不正确的。
If you try and combine the parts of C++ which are there so it behaves like C with the more strongly typed OO features, the looser typing in the C parts defeats the stronger typing in the C++ parts. It's best to keep them separate, or at least document the expected behaviours.
如果你尝试组合C ++的各个部分,那么它的行为就像C一样具有更强类型的OO特性,那么在C部分中更宽松的输入会破坏C ++部分中更强的类型。最好将它们分开,或者至少记录预期的行为。
#7
1
You're incremeneting the variable a
, which is a locally declared pointer of A objects. That's the same as saying a=a+sizeof(A)
.
您正在增加变量a,它是A对象的本地声明指针。这与a = a + sizeof(A)相同。
Since sizeof(B)>sizeof(A), you end up pointing into the middle of the first object. When C++ then adds the appropriate offset, it'll end up reading the c
field of the first B object. That happens to be unitialized memory, containing "junk".
由于sizeof(B)> sizeof(A),你最终指向第一个对象的中间。当C ++然后添加适当的偏移量时,它最终会读取第一个B对象的c字段。这恰好是整体记忆,包含“垃圾”。
#1
7
It can only know that at runtime. Imagine it slightly changed
它只能在运行时知道。想象一下它有点变化
A* a;
if(runtimevalue)
a = new A[10];
else
a = new B[10];
But that's not going to happen. C++ puts emphasize in speed, but this would basically make it into a language that ensures safety of operations. There is Java, C# and others that already solve this.
但那不会发生。 C ++强调速度,但这基本上使它成为一种确保操作安全的语言。有Java,C#等已经解决了这个问题。
Kernel and device driver developers don't want a clever language runtime. They just want to have things run fast.
内核和设备驱动程序开发人员不希望有一个聪明的语言运行时。他们只是想让事情快速发展。
Have a look at Common undefined behavior in C++ question for all the things that will need to get "fixed" along. It won't be C++ anymore!
在C ++问题中查看需要“修复”的所有内容的常见未定义行为。它不再是C ++了!
#2
19
No it shouldn't. The declared type of pA
is A*
, so it is incremented by sizeof(A)
, which leaves it pointing to the middle of the first B in the array.
不,不应该。声明的pA类型是A *,因此它增加sizeof(A),使其指向数组中第一个B的中间。
#3
11
The reason it's fragile is that you're side-stepping everything it does to try to keep you safe. Until you're sufficiently experienced to know why these problems are arising, and how to avoid them, you should:
它之所以脆弱,是因为你踩着它所做的一切,试着保证你的安全。除非你有足够的经验知道为什么会出现这些问题,以及如何避免这些问题,你应该:
- Forget that
printf
exists. Usestd::cout
instead. - Forget that
new
exists. Usestd::vector
instead.
忘记printf存在。请改用std :: cout。
忘记新的存在。请改用std :: vector。
You should probably also read the C++ FAQ, and pay close attention to the part that says something to the effect that: "Even if an X is a Y, an array of X is not an array of Y."
您可能还应该阅读C ++常见问题解答,并密切关注那些说明效果的部分:“即使X是Y,X的数组也不是Y的数组。”
Edit: As to why you're seeing the behavior you are, it's pretty simple: pointer arithmetic is defined in terms of the static type, not the dynamic type. That means it's based entirely on the type of pointee you defined for the pointer, NOT what it's pointing at. If you say it's pointing at an A, but then point it at a B, the arithmetic will still be done as if it was pointing at an A as you said it would.
编辑:至于为什么你会看到你的行为,这很简单:指针算术是根据静态类型而不是动态类型定义的。这意味着它完全基于您为指针定义的指针类型,而不是它指向的内容。如果你说它指向一个A,但是然后将它指向一个B,算术仍然会像你所说的那样指向一个A。
#4
3
Pointer a
points to an object that has static type A
and dynamic type B
. Pointer arithmetic in C++ works in terms of static type. So, from the point of view of pointer arithmetic, a
points to an object of type A
.
指针指向具有静态类型A和动态类型B的对象.C ++中的指针算法在静态类型方面起作用。因此,从指针算法的角度来看,指向A类型的对象。
#5
1
the objects have no record of what or how large they are, it's just allocated memory. The only way the compiler knows how to treat the object at the pointer memory, is by looking at the pointer type. So based on pointer A*, it will only assume an object of sizeof(A).
对象没有记录它们是什么或有多大,它只是分配了内存。编译器知道如何处理指针内存中对象的唯一方法是查看指针类型。因此,基于指针A *,它将仅假设sizeof(A)的对象。
#6
1
For reasons of compatibility with C arrays degrade to pointers. The type of B[10]
may degrade to B*
, and inheritance means that the assignment of a pointer to B
to a variable of type A*
is valid.
出于与C数组兼容的原因,降级为指针。 B [10]的类型可能降级为B *,继承意味着将指向B的指针分配给类型A *的变量是有效的。
You then increment the value of this pointer, which adds the size of A
to its address.
然后,您可以递增此指针的值,这会将A的大小添加到其地址。
However, your assumption that incrementing a pointer is a valid operation if the pointer is not pointing to an array of elements of the type of the pointer is not correct.
但是,如果指针未指向指针类型的元素数组,则假设递增指针是有效操作是不正确的。
If you try and combine the parts of C++ which are there so it behaves like C with the more strongly typed OO features, the looser typing in the C parts defeats the stronger typing in the C++ parts. It's best to keep them separate, or at least document the expected behaviours.
如果你尝试组合C ++的各个部分,那么它的行为就像C一样具有更强类型的OO特性,那么在C部分中更宽松的输入会破坏C ++部分中更强的类型。最好将它们分开,或者至少记录预期的行为。
#7
1
You're incremeneting the variable a
, which is a locally declared pointer of A objects. That's the same as saying a=a+sizeof(A)
.
您正在增加变量a,它是A对象的本地声明指针。这与a = a + sizeof(A)相同。
Since sizeof(B)>sizeof(A), you end up pointing into the middle of the first object. When C++ then adds the appropriate offset, it'll end up reading the c
field of the first B object. That happens to be unitialized memory, containing "junk".
由于sizeof(B)> sizeof(A),你最终指向第一个对象的中间。当C ++然后添加适当的偏移量时,它最终会读取第一个B对象的c字段。这恰好是整体记忆,包含“垃圾”。