Problem Solution: Inheritance And Whole-Part Relationships

class Employee : public Person					// Inheritance
{
	private:
		Record		myRecord;			// Composition
		Project*	myProject = nullptr;		// Aggregation
		int		id;

	public:
		Employee(string name, double s, int i)
			: Person(name), myRecord(s), id(i) {}

		friend ostream& operator<<(ostream& out, Employee& me)
		{
			out << (Person &)me << endl;					// (a)
			out << me.myRecord << endl;					// (b)
			if (me.myProject != nullptr) out << *me.myProject << endl;	// (c)
			out << me.id << endl;						// (d)

			return out;
		}
};

The Person, Project, and Record member variables are private, so they cannot be accessed directly from the Employee class. The Employee class must use the public interfaces (i.e., the public member functions) of the superclass and the two part classes to access their private members. The exact formatting (e.g., spaces and new lines) is not logically significant.

  1. Inheritance: The inserter casts the me parameter from an Employee to a Person, so that out << (Person &)me matches the Person inserter function parameter list.
  2. Composition: The Employee inserter calls the Record inserter using its me parameter and myRecord member variable.
  3. Aggregation: The Employee inserter calls the Project inserter function if myProject is not null. Attempting to call a function with a null pointer causes a runtime error, but the test prevents the error, improving reliability and security.
  4. Finally, the Employee inserter prints it id.