Once we understand how to build and use class relationships, we can begin constructing programs incorporating many classes connected by any appropriate relationships. This version of the Actor example starts with the three-level inheritance hierarchy developed in the Actor 1 example and adds two classes illustrating two kinds of whole-part relationships. Class Address is embedded inside class Person while class Date is made a part of Person with a pointer. The UML class diagram in the following figure shows the relationships between all the program classes:
The Actor 3 Part Classes
Class developers can implement a whole-part relationship with composition or aggregation. Both are one-way relationships, meaning that the part class "does not know about" the whole class. The source code for the part classes in this example reflects this situation by not referencing the whole class - the name Person does not appear in either class specification.
Address.h
Date.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
class Address
{
private:
string street;
string city;
public:
Address(string s, string c) : street(s), city(c) {}
void display()
{
cout << street << " " << city << endl;
}
};
#pragma once
#include <iostream>
using namespace std;
class Date
{
private:
int year;
int month;
int day;
public:
Date(int y, int m, int d)
: year(y), month(m), day(d) {}
void display()
{
cout << year << " " << month <<
" " << day << endl;
}
};
The Actor 3 Address and Date classes. Address and Date are terminal classes in the sense that they are parts of the Person class but do not participate in other relationships. The program pushes data into them through their constructors and pulls them through their display functions, but the constructors and display functions are not chained (i.e., do not call) other problem-domain functions. (Actor 3 treats the string class as a fundamental or built-in type.)
Actor 3 Person class
void Person::setDate(int y, int m, int d)
{
if (date != nullptr)
delete date;
date = new Date(y, m, d);
}
void Person::setDate(Date* d)
{
if (date != nullptr)
delete date;
date = d;
}
(a)
(b)
Aggregation setter function options. Programmers can create two kinds of setter functions to manage aggregation:
Creates a new Date object from "raw" data.
Install an existing Date object passed in by pointer.
Although classes can include both versions as overloaded functions, they typically only need one, and the problem determines which is most appropriate. Modern C++ compilers make the if-test, if (date != nullptr), optional.
Actor 3 Inheritance
The inheritance syntax in the Actor 3 example is unchanged from Actor 1. However, the number of constructor parameters is different. The example begins when the program instantiates a Star object, passing the initializing data through a chain of constructor calls. In the current example, the data now includes values to initialize the part objects instantiated from Address and Date.
Downloadable Code
Tab stops are set at 4 spaces - the default for the Visual Studio editor.