Aggregation (Composition) of Classes

    Static Data Members
    Operator Overloading

    Reading: Dietel 7.3, 7.7

Making new classes from previous ones

Implicit functionality of aggregated classes

Constructors

class MyType 
{
    private:  string name; Array a;
    public:  
                 MyType ( string s, int size );  // constructor
}

MyType :: MyType ( string s, int size ) : name ( size ), a ( size )  {  }  // No other initialization necesary

Invokes non-default constructors for string and Array member
Without initialization list: call default constructors, then need to reassign


Destructors

Copy Constructors

Assignment Operators

Example: Movie class

                        Movie.h

class Movie
{
    public:
                Movie ( );       // Constructors
                Movie ( string title_parameter );
                Movie ( string title_parameter, int n_stars );

                Movie ( const Movie& rhs );    // Copy constructor

                ~Movie ( );    // Destructor

                // Binary operators: implicit first parameter of type Movie

                Movie& operator = ( const Movie& rhs );    // Overload =

                bool operator == ( const Movie& rhs );  // Overload equality

                bool operator != ( const Movie& rhs ); // Overload inequality -- doesn't come with ==

                string GetTitle (  ) const;
                string GetStar ( int index = 0 ) const;
                int GetNumStars ( ) const;
                int GetID ( ) const;

                void SetTitle ( string title_parameter );
                void SetStar ( string name, int index );

                // No SetID (  ); we want to enforce unique IDs

    private:
                string title;
                string* stars;
                int num_stars;
                int ID;
                static int nextID;  // Next available ID; enforce uniqueness
                                          // Only one copy for the whole class, not each instantiation
}

// Also keep this prototype in Movie.h ; see below
ostream& operator << ( ostream& o, const Movie& rhs )

           Movie.cpp

int Movie :: nextID = 1; // No assignments possible within class definition
                                    // Must assign a value exactly once

        // Two possible parameterless constructors:

Movie :: Movie ( )
{
    ID = nextID ++;
    stars = 0;  // represent a null pointer
    num_stars = 0;

    // Default string constructor called: title is empty string   
}
                OR

Movie :: Movie ( ) : title ( "No title" )
{
    ID = nextID ++;
    stars = 0;
    num_stars = 0;

    // Could also have said: title = string("No title"); in constructor body
}
               

Movie :: Movie ( string title_parameter ) : title ( title_parameter )
{
   ID = nextID ++;
   stars = 0;
   num_stars = 0;
}

Movie :: Movie ( string title_parameter, int n_stars ) : title ( title_parameter )
{
    ID = nextID ++;
    num_stars = n_stars;
    stars = new string [ n_stars ];  // Each string default initialized by new
}

Movie :: Movie ( const Movie& rhs ) : title ( rhs.title )
{
    ID = rhs.ID;
    num_stars = rhs.num_stars;
    stars = new string [ num_stars ]; // Default constructor used here for each string

    for ( int i=0; i < num_stars; i++)
        stars [ i ] = rhs.stars [ i ]; // Overloaded = used here for each string
}

Movie :: ~Movie ( )
{
    delete [ ] stars;  // Has no effect on null pointers

    // string destructor will be called on title and each element of stars array
}

string Movie :: GetTitle ( ) const
{
    return title;
}

int Movie :: GetNumStars ( ) const
{
    return num_stars;
}

string GetStar ( int index ) const
{
    if ( 0 <= index && index < num_stars )
        return stars [ index ];

    return string("Error: index out of range."); // Explicit constructor call
    // Could also throw an exception
}

int Movie :: GetID ( ) const
{
    return ID;
}

void Movie :: SetTitle ( string title_parameter )
{
    title = title_parameter;  // overloaded string assignment used
}

void Movie :: SetStar ( string title_parameter, int index )
{
    if ( 0 <= index && index < num_stars )
        stars [ index ] = title_parameter;

    // Could throw an exception if index out of range
}

Movie& Movie :: operator = ( const Movie& rhs )
{
    if ( this != &rhs )  // Don't clobber on self-assignment
    {
       ID = rhs.ID;
       num_stars = rhs.num_stars;
       title = rhs.title;       // Assignment operator for string used here

       delete [ ] stars;
       stars = new string [ num_stars ] ; // Default constructor for each string used here
       if ( stars == 0 )
            num_stars = 0;  // Or could throw an exception
    }

    return *this;
}

bool Movie :: operator == ( const Movie& rhs )
{
    return ( ID == rhs.ID );
}

    // Could also use: if ( this.ID == rhs.ID ) return true;  else return false;

bool Movie :: operator != ( const Movie& rhs )
{
    return ! ( *this == rhs );
}

    // Could also use: if ( this.ID != rhs.ID ) return true;  else return false;

// Overload << for Movie objects : cout << M;
// Cannot be a member function / operator of Movie, since lhs is of type ostream, not Movie
// Can keep in Movie.cpp ; part of interface to Movie class

ostream& operator << ( ostream& o, const Movie& rhs )
{
    o << "Title: " << rhs.GetTitle( ) << endl;   // String class has also overloaded <<

    o << "Stars: " << endl;
    for ( int i=0; i < rhs.GetNumStars ( ); i++ )
        o << rhs.GetStar ( i ) << " ";   

    return o;
}