我正在尝试实现下面的函数和类,但是arr [i] .x的输出是错误的。我正确得到arr [0] .x = 0和arr [1] .x = 0,但arr [2] .x不返回0.任何想法为什么?
class Base {
public:
int x;
};
class Derived : public Base {
public:
int y;
void init(Base *b);
void foo();
};
void Derived :: init(Base *b) {
for( int i = 0; i < 3; ++i) {
b[i].x = 0;
}
}
void Derived :: foo() {
Derived arr[3];
init(arr);
for( int i = 0; i < 3; ++i) {
cout<<"b["<<i<<"] "<<arr[i].x;
}
}
int main()
{
Derived der;
der.foo();
return 0;
}
答案 0 :(得分:2)
void Derived :: foo() {
Derived arr[3];
init(arr);
指向Derived
,Derived*
的指针将传递给函数init(Base *b)
。接下来会发生什么,而不是按表格中的sizeof(Derived)=8
移动,您的函数将移动sizeof(Base)=4
,导致数组中第一个和第二个x
的{{1}}成员初始化以及Derived
的{{1}},但不是最后y
的{{1}}。
指针算法是根据类型的大小完成的 指针
考虑这个内存布局(在x64上):
Derived :: foo()中的Derived
x
因此,您已将arr [0] .x设置为0,将arr [1] .x设置为0,并将arr [0] .y设置为0.这不是您想要的。解决方案是将Derived :: init更改为
Derived
甚至更好,遵循更通用的编程原则:
Derived arr[3];
0x7fffffffe310 // 1st Derived, also address of arr[0].x
+8 =
0x7fffffffe318 // 2nd Derived, also address of arr[1].x
+8 =
0x7fffffffe320 // 3rd Derived, also address of arr[2].x
答案 1 :(得分:1)
原因是init()不知道你实际上是在传递Derived *而不是Base *。
所以init()函数中的循环,假设为了到达数组中的下一个条目,sizeof(Base)被添加到指针,而不是sizeof(Derived)。
答案 2 :(得分:0)
变化
cout<<"b["<<i<<"] "<<arr[i].x;
到
cout<<"b["<<i<<"] "<<arr[i].x<<endl;
然后你会看到正确的号码。
endl的额外功能是刷新与此流关联的缓冲区。如果你不这样做,它有时会输出一些随机数。
答案 3 :(得分:-1)
对于一个你通过值而不是通过引用将指针(* b)传递给函数init()。
Here's a nice explanation as to why that matters他们解释得比我可能更好
尝试使init函数看起来像这样
init(Base& *b)
看看会发生什么。