【问题标题】:Some trouble with derived classes [duplicate]派生类的一些问题[重复]
【发布时间】:2014-04-13 22:49:08
【问题描述】:

我正在尝试实现下面的函数和类,但是 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;
}

【问题讨论】:

    标签: c++ arrays class oop object


    【解决方案1】:
    void Derived :: foo() { 
        Derived arr[3];
        init(arr);
    

    指向DerivedDerived* 的指针被传递给函数init(Base *b)。接下来发生的事情是,您的函数不会移动表中的sizeof(Derived)=8,而是移动sizeof(Base)=4,这会导致数组中第一个和第二个Derivedx成员以及第一个@的y的初始化987654330@,但不适用于最后一个Derivedx

    指针运算是根据类型的大小来完成的 指针

    考虑这种内存布局(在 x64 上):

    在 Derived::foo():

    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
    

    但在 Derived::init(Base* b):

    b[0].x = 0x7fffffffe310  // set arr[0].x to 0
    +4 =
    b[1].x = 0x7fffffffe314  // set arr[0].y to 0
    +4 =
    b[2].x = 0x7fffffffe318  // set arr[1].x to 0
    

    因此,您已将 arr[0].x 设置为 0,将 arr[1].x 设置为 0,顺便将 arr[0].y 设置为 0。这不是您想要的。解决方案是将 Derived::init 更改为

    void Derived::init( Derived *d) {
      for( int i = 0; i < 3; ++i) {
        d[i].x = 0;
      }
    }
    

    甚至更好,遵循更通用的编程原则:

    template < size_t N>
    void Derived::init( Derived (&d)[N] ) {
        for( int i = 0; i < N; ++i) {
            d[i].x = 0;
        }
    }
    

    【讨论】:

      【解决方案2】:

      原因是 init() 不知道您实际上传递的是 Derived* 而不是 Base*。

      所以 init() 函数中的循环,假设要到达数组中的下一个条目,将 sizeof(Base) 添加到指针,而不是 sizeof(Derived)。

      【讨论】:

        【解决方案3】:

        改变

        cout<<"b["<<i<<"] "<<arr[i].x;
        

        cout<<"b["<<i<<"] "<<arr[i].x<<endl;
        

        然后你会看到正确的数字。

        endl 的额外功能是刷新与此流关联的缓冲区。如果你不这样做,它有时会输出一些随机数。

        【讨论】:

          【解决方案4】:

          你通过值而不是引用将指针 (*b) 传递给函数 init()。

          Here's a nice explanation as to why that matters他们解释得比我可能做得更好

          试着让函数 init 看起来像这样

          init(Base& *b)
          

          看看会发生什么。

          【讨论】:

          • 函数不想改变指针。
          猜你喜欢
          • 1970-01-01
          • 2010-09-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-03
          • 2012-10-14
          • 1970-01-01
          相关资源
          最近更新 更多