// ==========================================================================
// $Id: copycontrol.cpp,v 1.5 2016/11/02 18:13:25 jlang Exp $
// CSI2372 example Code for lecture 12
// ==========================================================================
// (C)opyright:
//
//   Jochen Lang
//   SITE, University of Ottawa
//   800 King Edward Ave.
//   Ottawa, On., K1N 6N5
//   Canada. 
//   http://www.site.uottawa.ca
// 
// Creator: jlang (Jochen Lang)
// Email:   jlang@site.uottawa.ca
// ==========================================================================
// $Log: copycontrol.cpp,v $
// Revision 1.5  2016/11/02 18:13:25  jlang
// Added stack example for copy control
//
// Revision 1.4  2016/10/17 16:28:31  jlang
// Updated for showing effects of access modifiers and using declaration.
//
// Revision 1.3  2008/11/15 01:09:18  jlang
// Base destructor should be virtual
//
// Revision 1.2  2008/11/15 01:04:17  jlang
// Added alternative assignment of base
//
// Revision 1.1 2008/11/15 01:01:23 jlang 
// Example of assignment operator, copy constructor and destructor
// overloading with class hierarchies
//
//
// ==========================================================================

#include <iostream>
#include <string>

using std::string;
using std::cout;
using std::endl;


class Base {
protected:
  string d_name;
public:
  Base( const string& _name = string("Hello") ) : d_name(_name)
  {}
  // Just for printing
  Base( const Base&  oB ) : d_name( oB.d_name ) {
    cout << "Base copy constructor!" << endl;
  }
  // Just for printing
  Base& operator=( const Base&  oB ) { 
    cout << "Base assignment operator!" << endl;
    // Check for self-assignment
    if ( this != &oB ) {
      d_name = oB.d_name;
    }
  }
  // get the name
  inline string getName() {
    return d_name;
  } 
  // Just for printing
  virtual ~Base() {
    cout << "Base destructor!" << endl;
  }
};


class Derived : private Base {
  int d_size;
  int* d_array;
public:
  Derived( int _size ) : Base("Null"), d_size(_size) {
    d_array = new int[_size];
  }
  // set all of the array to value
  Derived& operator=( int val ) {
    for ( int i=0; i<d_size; ++i ) {
      d_array[i] = val;
    }
    return *this;
  }
  // set the name
  inline void setName( const string& _name ) {
    d_name = _name;
  }
  // C++11 using to "copy" a function into the derived class
  using Base::getName;
  // Copy Constructor with pointer member
  Derived( const Derived& oD ) : Base(oD), d_size(oD.d_size) {
    cout << "Derived copy constructor!" << endl;
    d_array = new int[d_size];
    for ( int i=0; i<d_size; ++i ) {
      d_array[i] = oD.d_array[i];
    }
  }
  // Assignment operator with pointer member
  Derived& operator=( const Derived& oD ) {
    cout << "Derived assignment operator!" << endl;
    // Check for self-assignment
    if ( this != &oD ) {
      Base::operator=(oD);
      // this works too:
      // static_cast<Base>(*this) = oD; 
      delete [] d_array;
      d_size = oD.d_size;
      d_array = new int[d_size];
      for ( int i=0; i<d_size; ++i ) {
	d_array[i] = oD.d_array[i];
      }
    }
    return *this;
  }
  // Destructor with pointer member
  ~Derived() {
    cout << "Derived destructor!" << endl;
    delete [] d_array;
  }
};


int main() {
  Derived vec5(5);
  // Set all values to 5
  vec5 = 5;
  vec5.setName("All 5");
  cout << "Step 1" << endl;
  //----------------
  Derived tmp(7);
  tmp = 7;
  tmp.setName("All 7");
  cout << "Step 2" << endl;
  // Copy construct
  cout << "Now cctor" << endl;

  Derived vec7(tmp);
  cout << vec7.getName() << endl;
  //----------------
  // Assignment
  cout << "Now assignment" << endl;

  tmp = vec5;
  cout << tmp.getName() << endl;
  tmp = tmp;
  tmp = 3;
  return 0;
}
