#include <iostream>
using namespace std;


class IntArray {
  friend class IntArrayIter;
public:
  void init();
  void cleanup();
  void setSize( size_t value );
  size_t getSize();
  void setElem( size_t index, int value );
  int getElem( size_t index );
private:
  int *elems;
  size_t numElems;
}; // end of class IntArray


class IntArrayIter {
public:
  void init();
  void cleanup();
  void setIter( IntArray *array );
  void goFirst();
  void goNext();
  int getCur();
  int curIsValid();
private:
  IntArray *array;
  size_t curItem;
}; // end of class IntArrayIter


class StatsIntArray : public IntArray {
public:
  int mean();
private:
  int *buf;
}; // end of class StatsIntArray


// IntArray member functions

void IntArray::init() {
  numElems = 0;
  elems = 0;
} // end of IntArray::init()

void IntArray::cleanup() {
  free( elems );
  elems = 0;
  numElems = 0;
} // end of IntArray::cleanup()

void IntArray::setSize( size_t value ) {
  if ( elems != 0 ) {
    free( elems );
  }
  numElems = value;
  elems = (int *)malloc( value * sizeof( int ));
} // end of IntArray::setSize()

size_t IntArray::getSize() {
  return( numElems );
} // end of IntArray::getSize()

void IntArray::setElem( size_t index, int value ) {
  if (( index < -0 ) || ( index >= numElems )) {
    cerr << "bad index";
    exit( 1 );
  }
  elems[index] = value;
} // end of IntArray::setElem()

int IntArray::getElem( size_t index ) {
  if (( index < -0 ) || ( index >= numElems )) {
    cerr << "bad index";
    exit( 1 );
  }
  return( elems[index] );
} // end of IntArray::getElem()



// IntArrayIter member functions

void IntArrayIter::init() {
  array->init();
} // end of IntArrayIter::init()

void IntArrayIter::cleanup() {
  array->cleanup();
  array = 0;
} // end of IntArrayIter::cleanup()

void IntArrayIter::setIter( IntArray *array ) {
  this->array = array;
  goFirst();
} // end of IntArrayIter::setIter()

void IntArrayIter::goFirst() {
  curItem = 0;
} // end of IntArrayIter::goFirst()

void IntArrayIter::goNext() {
  curItem++;
} // end of IntArrayIter::goNext()

int IntArrayIter::getCur() {
  if ( ! curIsValid() ) {
    cerr << "no current item\n";
    exit( 1 );
  }
  return curItem;
} // end of IntArrayIter::getCur()

int IntArrayIter::curIsValid() {
  return (( array != 0 ) &&
	  ( curItem >= 0 ) && 
	  ( curItem < array->numElems ));
} // end of IntArrayIter::curIsValid()



// StatsIntArray member functions

int StatsIntArray::mean() {
  int total = 0;
  IntArrayIter iter;
  iter.setIter( this );
  for ( iter.goFirst(); iter.curIsValid(); iter.goNext() ) {
    total += getElem( iter.getCur() );
  }
  return( total / getSize() );
} // end of StatsIntArray::mean()



int main() {
  StatsIntArray powersOf2;
  IntArrayIter iter;
  powersOf2.init();
  powersOf2.setSize( 8 );
  powersOf2.setElem( 0, 1 );
  iter.setIter( &powersOf2 );
  iter.goFirst();
  for ( iter.goNext(); iter.curIsValid(); iter.goNext() ) {
    powersOf2.setElem( iter.getCur(), 2*powersOf2.getElem( iter.getCur()-1 ));
  }
  cout << "here are the elements:\n";
  for ( iter.goFirst(); iter.curIsValid(); iter.goNext() ) {
    cout << "powerOf2=" << powersOf2.getElem( iter.getCur() ) << "\n";
  }
  cout << "mean = " << powersOf2.mean() << "\n";
  iter.cleanup();
  powersOf2.cleanup();
}

