Composition: The "Has a" Relationship


It is common for a C++ class to have objects of other C++ classes as data members. For example, we might define a Course class to encapsulate a collection of students. The new Course could have an array of Student objects as one of its data members. This relationship between a Course object and the Student objects that are its data members is called a "has a" relationship. A Course object "has" an array of Student objects.

This has some obvious advantages over simply creating an array of Student objects as a local variable of a function. We can include additonal state information in the Course class, such as the course name and number. We can create additional courses simply by declaring additional Course objects.

Here is a full program example illustrating the creation and use of Student and Course objects:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <string>

using std::cerr;
using std::cout;
using std::endl;
using std::fixed;
using std::ifstream;
using std::setprecision;
using std::string;

// Student class definition
class Student
{
private:
    
    char name[31]{"None"};
    double gpa{0.0};
    
public:
    
    // Constructors
    Student() = default;
    Student(const char*, double);
    
    // Accessor and mutator member functions
    void set_name(const char*);
    const char* get_name() const;
    void set_gpa(double);
    double get_gpa() const;
    
    // Other member functions
    void print() const;
};

// Course class definition
class Course
{
private:
    
    char name[31]{"None"};
    char course_number[11]{"None"};
    Student class_list[45];
    int num_students = 0;
    
    void sort_class_list();
    
public:
    
    // Constructors
    Course() = default;
    Course(const char*, const char*);

    // Other member functions    
    void read_student_data(const string&);
    void print() const;
};

int main()
{
    Course course1("CSCI 240", "Introduction to Programming");
    Course course2("CSCI 241", "Intermediate Programming");
    
    course1.read_student_data("students1.txt");
    course1.print();
    
    cout << endl;
    
    course2.read_student_data("students2.txt");
    course2.print();
    
    return 0;
}

// Student constructor

Student::Student(const char* new_name, double new_gpa)
{
    set_name(new_name);
    set_gpa(new_gpa);
}

// Student accessor and mutator member functions
 
void Student::set_name(const char* new_name)
{
    strcpy(name, new_name);
}

const char* Student::get_name() const
{
    return name;
}

void Student::set_gpa(double new_gpa)
{
    if (new_gpa < 0.0)
        gpa = 0.0;
    else if (new_gpa > 4.0)
        gpa = 4.0;
    else
        gpa = new_gpa;
}

double Student::get_gpa() const
{
    return gpa;
}

// Other Student member functions

void Student::print() const
{
    cout << "Name: " << name << endl
         << "GPA: " << fixed << setprecision(2) << gpa << endl;
}

// Course constructor

Course::Course(const char* new_course_number, const char* new_name)
{
    strcpy(name, new_name);
    strcpy(course_number, new_course_number);
    num_students = 0;
}

// Other Course member functions

void Course::read_student_data(const string& file_name)
{
    ifstream in_file;
    char first_name[11], last_name[21], name[31];
    double gpa;
    
    // Open the input file and test for failure
    in_file.open(file_name);
    if (!in_file)
    {
        cerr << "Error - unable to open input file " << file_name << endl;
        exit(1);
    }
    
    in_file >> first_name;
    while (in_file)
    {
        in_file >> last_name;
        in_file >> gpa;
        
        strcpy(name, last_name);
        strcat(name, ", ");
        strcat(name, first_name);

        // Create a Student object and copy it into
        // the array.
        class_list[num_students] = Student(name, gpa);
        
        num_students++;
        
        in_file >> first_name;
    }
    
    in_file.close();

    sort_class_list();
}

void Course::sort_class_list()
{
    int i, j, min;
    Student temp;
    
    for (i = 0; i < num_students - 1; i++)
    {
        min = i;
        
        for (j = i+1; j < num_students; j++)
        {
            if (strcmp(class_list[j].get_name(), class_list[min].get_name()) < 0)
                min = j;
        }
        
        temp = class_list[i];
        class_list[i] = class_list[min];
        class_list[min] = temp;
    }
}

void Course::print() const
{
    int i;
    
    cout << course_number << " " << name << endl << endl;
    
    for (i = 0; i < num_students; i++)
    {
        class_list[i].print();
        cout << endl;
    }
}

Download the full program example, including a makefile and sample data files