输出混乱

时间:2009-10-04 12:03:35

标签: c++

考虑以下计划。

#include<iostream>
using namespace std;

class base
{

   public:
     int _bval;

     base():_bval(0){}
};

class derived:public base
{

   public:
     int _dval;

     derived():base(),_dval(1){}
};

int main()
{     

   derived d[5];
   base *p;
   p=d;
   for(int i=0;i<5;++i,++p)
      cout<<p->_bval;

}

上述程序的输出为01010 我认为输出将是00000,因为_bval的值被基类构造函数初始化为0(每次)。

但为什么输出与00000不同?
我错过了什么?

4 个答案:

答案 0 :(得分:11)

p[i]sizeof(base) * i后的p字节提供值。所以p[1]不会给你d的第二个元素,它会给你第一个元素的后半部分。

换句话说:如果使用指向基类的指针迭代派生类的数组,如果派生类的大小比基类大,则会得到错误的结果,因为它会逐步迭代sizeof(baseclass)个字节。

答案 1 :(得分:7)

简短回答:在C ++中,值的数组永远不会是多态的,即使它们的内容是,也不能这样处理。也就是说,您无法将derived ad[N]视为base ab[N]

答案很长:其原因深深植根于C的指针算法中。如果你有int* pi并将其递增++pi,它将不会简单地递增到下一个内存地址。如果确实如此,则不会指向下一个int,因为它不会从下一个地址开始。因此,将sizeof(int)个字节添加到指针中。 (一个具体的例子可能会有所帮助:在8位char类型的架构中 - char,根据定义,C和C ++考虑架构的字节大小 - 以及32位int类型,{{1}因此,int将向指针地址添加4,以便指向下一个++pi。)相同的算法适用于所有其他指针操作。因此,例如,使用int时,int* pi2=pi+1会将pi2字节指向sizeof(int),但pi将产生1。

所以,假设你理解了最后一段,让我们回到数组。如果您有一个数组pi2-pi,则derived ad[N]的地址比ad[1]的地址大sizeof(derived)个字节。 (这是为了不使问题进一步复杂化而忽略对齐。)但是,如果ad[0]指向base* pb,则递增它将使其指向ad[0]后面的地址。第一个元素 - 如果(在您的示例中为sizeof(base),则 sizeof(base) < sizeof(derived)的地址,但在ad[1]的中间位置。

唯一可以将数组内容视为所有基类的方法是使用ad[0]迭代数组并将此指针转换为<{1}} / em>循环:

derived*

(请注意,我还更改了您的代码以使用C ++'惯用的开始/结束迭代器。)

答案 2 :(得分:3)

想想d数组的内存布局。

D-&GT; 0101010101

每对01对应一个派生对象。

现在让我指出它:

对 - &GT; 0101010101

由于基础对象的大小是一个int的大小。该内存段被认为是10个基础对象:第一个使用_bval 0,第二个使用_bval 1,等等。

答案 3 :(得分:1)

除了sepp2k所说的,你没有在派生类构造函数中初始化_bval。您应该使用base构造函数初始化它。