#include "iostream.h"

// ================= CLASS A =======================

class A 
{
  friend ostream& operator<<(ostream &, A&);  // Friend (output) operator >>
  friend void operator>(int &, A&);           // Friend opeator > 1
  public:
    A() {count=1; a=new int; *a=0;};   // Constructor 1
    A(int i,int j=2);                  // Constructor 2
    A(const A&);                       // Constructor 3 (Copy Constructor)
    ~A() {cout<<"DEL A\n"; delete a;}  // Destructor
    int sum();                         // Member function 
    void operator>(A&);                // Member operator > 2
  private:
    int count;           // Array size
    int *a;              // Dynamically created array
};

void operator>(int &i, A& pa)  // Friend operator > 1 (for assignment)
{
  cout<<"ASSIGN 1\n";
  delete pa.a;
  pa.count = i;
  pa.a=new int[i];
  for (int k=0;k<i;k++)
    pa.a[k]=0;
}

ostream& operator<<(ostream & os, A & ax) // Friend (output) operator >>
{
  os<<"* "<<ax.count<<" "<<ax.sum()<<"\n";
  return os;
}

A::A(int i,int j=2)            // Constructor 2
{
  count =i; 
  a=new int[i]; 
  for (int k=0;k<i;k++) 
    a[k]=j;
}

A::A(const A& pa)              // Constructor 3 (Copy Constructor)
{
  count = pa.count;
  a=new int[count];
  for (int k=0;k<count;k++)
    a[k]=pa.a[k];
}

void A::operator>(A& pa)       // Member operator > 2 (for assignment)
{
  cout<<"ASSIGN 2\n";
  delete pa.a;
  pa.count = count;
  pa.a=new int[count];
  for (int k=0;k<count;k++)
    pa.a[k]=a[k];
}

int A::sum()                   // Member function: sum of a[0]..a[count-1] 
{
  int tot=0; 
  for (int k=0;k<count;k++) 
    tot=tot+a[k]; 
  return tot;
}

// ================ CLASS B (composite class) ================

class B 
{
  friend ostream& operator<<(ostream &, B&); // Friend (output) operator >>
  public:
    B (int i):count(i+1), a(i+2) {};         // Constructor 1
	virtual void print();                    // Member funtion
  protected:
    int count;     // integer memeber field
    A a;           // A-typed  member field
};

ostream& operator<<(ostream & os, B & bx)    // Friend (output) operator >>
{
  cout<<"B<<* "<<bx.count<<"\n";
  cout<<bx.a;
  return os;
}

void B::print()                               // Member funtion
{
  cout<<"Bprint* "<<count<<"\n";
  cout<<a;
}

// ==================== CLASS C (derived class / subclass) ============

class C:public B 
{
  friend ostream& operator<<(ostream &, C&);  // Friend (output) operator >>
  public:
    C ():count(5),a(5),B(5) {};               // Constructor 1
	void print();                             // Member function
  private:
    int count;          // integer member field
    A a;                // A-typed member field
};

ostream& operator<<(ostream & os, C & cx)    // Friend (output) operator >>
{
  cout<<"C<<* "<<cx.count<<" "<<cx.B::count<<"\n";
  cout<<cx.a<<cx.B::a;
  return os;
}

void C::print()                               // Member function
{
  cout<<"Cprint* "<<count<<" "<<B::count<<"\n";
  cout<<a<<B::a;
}

// ============== ordinary functions ====================

void f1(B & bp)
{
  cout<<"---- f1 ----\n";
  cout<<bp;
  bp.print();
}

void f2(B bp)
{
  cout<<"---- f2 ----\n";
  cout<<bp;
  bp.print();
}

main()
{
  A a; 
  B b(3);
  C c;
  cout<<a<<b<<c;

  A *pa = new A(2);
  *pa > a;
  cout<<a<<*pa;

  int i=4;
  i > a;
  cout<<a;

  delete pa;

  b.print(); 
  c.print();

  f1(b);f1(c);
  f2(b);f2(c);
}
