C++. Types of relations between classes: is-a, has-a, uses. Examples. Inheritance. Basic concepts




C++. Types of relations between classes: is-a, has-a, uses. Examples


Contents


Search other websites:

1. Types of relationships between classes. Classification

Two types of relationships are possible between classes:

  • 1. A relationship of type is-a (is a relationship), in which one class is a subtype of another class. In this regard, one class expands (details) the capabilities of another class. The scope of the class is enhanced through the use of inheritance.
  • 2. A relation in which there is a relationship between two classes. Two subtypes of the relationship between classes are distinguished here:
    • 2.1. A has-a relationship (the class contains another class). In this case, one or more instances of another class are declared in the class. In this respect, two cases of interaction are possible. The first case is when the object (instance) that is declared in the class is not part of the class (aggregation) and its use does not affect the functional work of the class. The second case is when an object that is declared in a class is an integral part of this class (composition).
    • 2.2. A relation of type uses (class “uses a different class). In this case, the class contains the program code of another nested class to which it has access. More details about the features of using relations of type uses are described here.

 

2. An example of the simplest type of is-a relationship (inheritance)

The essence of an is-a relationship is that a class is a subspecies of another class. In this example, the Circle base class is extended by the CircleColor class. The CircleColor class is a subspecies of the Circle class and adds a color field to it.

The following elements are implemented in the Circle class:

  • internal private fields x, y, r;
  • constructor Circle() with 3 parameters that fill the values of internal fields;
  • access methods GetXYR(), SetXYR() to the class fields;
  • function Area() for calculating the area of a circle.

The CircleColor derived class implements fields and methods that complement the Color class:

  • internal private field color of class;
  • the CircleColor() constructor with 4 parameters, which calls the constructor of the Color class;
  • methods GetColor(), SetColor() to access the hidden variable color.

Demonstration text of the program in C++ as follows:

#include <iostream>
using namespace std;

// C++. Demonstration of the relationship is-a
// A class that implements a circle - the base class
class Circle
{
  // 1. Internal private fields of class
private:
  double x, y; // Circle center coordinates
  double r; // radius of the circle

public:
  // 2. Class constructor
  Circle(double x, double y, double r)
  {
    this->x = x;
    this->y = y;
    if (r > 0) this->r = r;
    else
      this->r = 1.0;
  }

  // 3. Access methods
  void GetXYR(double& x, double& y, double& r)
  {
    x = this->x;
    y = this->y;
    r = this->r;
  }

  void SetXYR(double x, double y, double r)
  {
    this->x = x;
    this->y = y;

    // correct radius, if necessary
    if (r > 0)
      this->r = r;
    else
      this->r = 1.0;
  }

  // 4. Function Area() - the area of a circle
  double Area()
  {
    const double Pi = 3.141592;
    return Pi * r * r;
  }
};

// A class that extends the capabilities 
// of the Circle class - adds color to the circle
class CircleColor : public Circle
{
  // 1. Internal variables of the class
private:
  unsigned int color = 0;

public:
  // 2. Constructor
  CircleColor(double x, double y, double r, unsigned int color) :Circle(x, y, r)
  {
    this->color = color;
  }

  // 3. Access methods
  unsigned int GetColor()
  {
    return color;
  }

  void SetColor(unsigned int color)
  {
    this->color = color;
  }
};

void main()
{
  // Demonstration of the relationship is-a between classes
  // 1. Class Circle
  // 1.1. Create an instance of class Circle
  Circle cr(1, 3, 2);

  // 1.2. Call the method Area() of class Circle
  double area = cr.Area();
  cout << "The instance of class Color:" << endl;
  cout << "area = " << area << endl;

  // 1.3. Get the value of instance cr
  double x, y, r;
  cr.GetXYR(x, y, r);

  // 1.4. Display the values on the screen
  cout << "x = " << x << ", y = " << y << ", radius = " << r << endl;

  // 2. The instance of class CircleColor
  // 2.1. Create an instance of CircleColor class
  CircleColor crCol(2, 4, 6, 1);

  // 2.2. Get the fields values of crCol instance
  // 2.2.1. get the value of color from method of CircleColor class
  unsigned int col = crCol.GetColor();

  // 2.2.2. Get the values x, y, r from method of base class Color
  crCol.GetXYR(x, y, r);

  // 2.3. Display the values on screen
  cout << "The instance of class ColorCircle: " << endl;
  cout << "color = " << col << endl;
  cout << "x = " << x << endl;
  cout << "y = " << y << endl;
  cout << "r = " << r << endl;

  // 2.4. Invoke the Area() method of base class Circle
  cout << "area = " << crCol.Area() << endl;
}

The result of the program

The instance of class Color:
area = 12.5664
x = 1, y = 3, radius = 2
The instance of class ColorCircle:
color = 1
x = 2
y = 4
r = 6
area = 113.097

 

3. Examples of a has-a relationship between classes

With a has-a relationship, a class contains one or more objects (instances) of another class. There are two kinds of has-a relationships:

  • aggregation. This is the case when one or more nested objects are not part of the class. A class can contain any number of such objects (even 0). For a better study of aggregation, see the examples below;
  • composition or union. In this case, one or more nested objects is part of the class, that is, without these objects, the logical existence of the class itself is impossible.





 

3.1. Aggregation examples for has-a relationship type

In the case of aggregation, a class contains many (one or more) objects of other classes that are not part of this class (do not contain code that complements the work of the class itself).

3.1.1. A shortened example. The Figures class contains instances of the Triangle and Circle classes.

This abbreviated code demonstrates aggregation using the Triangle, Circle, Figures classes as an example. The Figures class can contain a different number of different figures (even 0). Whenever possible, arrays of other figures can be added to the Figures class, for example, a Rectangle. In any case, the Figures class will be fully functional, which means that this is aggregation.

// Class that describes a triangle
class Triangle
{
  // Methods and fields of Triangle class
  // ...
};

// A class that implements a circle
class Circle
{
  // Methods and fields of Circle class
  // ...
};

// A class that implements various geometric figures.
// Used type of relationship - aggregation.
class Figures
{
  Triangle tr[10]; // array of triangles
  unsigned int n_tr; // the number of triangles in the array tr
  Circle cr[10]; // array of circles
  unsigned int n_cr; // the number of circles in the array cr

  // Other fields and class methods
  // ...
};

 

3.1.2. Example. The BusStation class contains arrays of instances of the Bus and Car classes

In the example, the BusStation class (Bus Station) contains arrays of instances of the Bus and Car classes. The number of elements in arrays of the Bus and Car classes can vary. Even if there is not a single bus or car at the bus station at a given time, the bus station will function. This is aggregation.

#include <iostream>
using namespace std;

// C++. The demonstration of has-a relationship
// The maximum possible number of vehicles at the bus station
const int MAX_VEHICLES = 10;

// Clas that describes a car
class Car
{
  // 1. Internal private fields of the class
private:
  string model; // car model

public:
  // 2. Class constructors
  // 2.1. The main constructor of the class with 1 parameter
  Car(string _model) :model(_model)
  {
  }

  // 2.2. Constructor without parameters,
  //      calls the main constructor
  Car() : Car("")
  {
  }

  // 3. Methods of access to class fields
  string GetModel() { return model; }
  void SetModel(string _model)
  {
    model = _model;
  }

  // 4. The method of displaying vehicle information
  void Print()
  {
    cout << "model = " << model << endl;
  }
};

// Class Bus
class Bus
{
  // 1. Internal hidden fields
private:
  string model; // Brand of the bus
  unsigned int seats; // number of seats

public:
  // 2. Constructors
  // 2.1. Constructor with 2 parameters - main constructor
  Bus(string _model, int _seats) : model(model), seats(_seats)
  {
  }

  // 2.2. Constructor without parameters,
  // calls the main constructor
  Bus() : Bus("", 0) {}

  // 3. Access methods
  void Get(string& _model, int& _seats)
  {
    _model = model;
    _seats = seats;
  }

  void Set(string _model, int _seats)
  {
    model = _model;
    seats = _seats;
  }

  // 4. Method that displays information about bus
  void Print()
  {
    cout << "model = " << model << ", seats = " << seats << endl;
  }
};

// Class BusStation - contains arrays of Bus, Car classes
class BusStation
{
private:
  Bus B[MAX_VEHICLES]; // an array of objects of class Bus
  unsigned int nBus; // current number of buses
  Car C[MAX_VEHICLES]; // array of objects of class Car
  unsigned int nCar; // current number of cars

public:
  // 1. Constructor without parameters
  BusStation()
  {
    nBus = nCar = 0;
  }

  // 2. Access methods processing an array of buses B[]
  // 2.1. Get information about bus by number
  Bus GetBus(unsigned int number)
  {
    // checking if the number is correct
    if (number < nBus)
      return B[number];
    else
    {
      cout << "Error. Incorrect number of a bus." << endl;
      return Bus("", 0);
    }
  }

  // 2.2. Add a new bus
  void AddBus(string model, unsigned int seats)
  {
    // check if a vehicle can be added
    if ((nCar + nBus) < MAX_VEHICLES)
    {
      nBus++; // increase the number of buses by 1
      B[nBus - 1].Set(model, seats); // invoke the method of Bus class
      cout << "A new bus is added!" << endl;
    }
    else
    {
      cout << "Cannot add a new bus. Sorry" << endl;
      return;
    }
  }

  // 2.3. Remove the bus from the bus station by its number
  void DelBus(unsigned int number)
  {
    if (number < nBus)
    {
      // cycle of displacement of elements of array B
      for (int i = number; i < nBus - 1; i++)
        B[i] = B[i + 1];
      nBus--;
    }
  }

  // 3. Access methods processing an array of cars C[]
  // 3.1. Get a car by its serial number
  Car GetCar(unsigned int number)
  {
    if (number < nCar)
      return C[number];
    else
    {
      cout << "Error. Incorrect number of a car." << endl;
      return Car("");
    }
  }

  // 3.2. Add a new car to the car park
  void AddCar(string model)
  {
    // Check if there is a parking space
    if ((nCar + nBus) < MAX_VEHICLES)
    {
      nCar++; // increase the number of cars
      C[nCar - 1].SetModel(model); // add the data of the vehicle
      cout << "A new car is added!" << endl;
    }
    else
    {
      cout << "Cannot add a new car. Sorry" << endl;
      return;
    }
  }

  // 3.3. Remove the car from the parking lot at the specified number
  void DelCar(unsigned int number)
  {
    if (number < nCar)
    {
      // Element shift cycle from position number
      for (int i = number; i < nCar - 1; i++)
        C[i] = C[i + 1];
      nCar--;
    }
  }

  // 4. A method that displays information about
  // currently located vehicles in a parking lot
  void Print()
  {
    cout << "Info about bus station:" << endl;
    cout << "nBus = " << nBus << endl;
    if (nBus > 0)
    {
      cout << "Info about buses:" << endl;
      for (int i = 0; i < nBus; i++)
      {
        B[i].Print();
      }
    }
    cout << "nCar = " << nCar << endl;
    if (nCar > 0)
    {
      cout << "Info about cars:" << endl;
      for (int i = 0; i < nCar; i++)
      {
        C[i].Print();
      }
    }
  }
};

void main()
{
  // Demonstration of using the BusStation class
  // 1. Declare the instance of class BusStation
  BusStation bs;

  // 2. Add some vehicles
  bs.AddBus("Mercedes Sprinter", 28);
  bs.AddBus("Renault Traffic", 29);
  bs.AddCar("Bentley");
  bs.AddCar("Renault Sandero");

  // 3. Display data about vehicles
  bs.Print();
}

The result of the program:

A new bus is added!
A new bus is added!
A new car is added!
A new car is added!
Info about bus station:
nBus = 2
Info about buses:
model = Mercedes Sprinter, seats = 28
model = Renault Traffic, seats = 29
nCar = 2
Info about cars:
model = Bentley
model = Renault Sandero

 

3.2. Examples of compositions for the relationship type has-a
3.2.1. A simplified example. The Car class, containing instances of the Vehicle and Wheel classes

The example demonstrates the composition for the classes Vehicle, Wheel, Car. The car (class Car) includes the engine (Vehicle class) and the wheel (Wheel), which are its integral part – it is a composition.

// Class Vehicle
class Vehicle
{
  // Fields and methods of the class
  // ...
};

// Class Wheel
class Wheel
{
  // Fields and methods of the class
  // ...
};

// Car class - contains required elements,
// which are the components of Automobile
class Car
{
  // Instances of required classes
  // that are part of this class are composition
private:
  Vehicle veh; // car contains engine (required)
  Wheel whl[4]; // car contains engine (required)

  // Fields and methods of the class
  // ...
};

 

3.2.2. A simplified example. The Bike class contains instances of the Wheel and Saddle classes.

Another example of composition. The Bike class contains instances of the Wheel and Saddle classes, which are part of it. A bicycle cannot be without wheels or a saddle, therefore it is a composition.

// Class Wheel
class Wheel
{
  // Fields and methods of the class
  // ...
};

// Class Saddle
class Saddle
{
  // Fields and methods of the class
  // ...
};

// The Bicycle class, contains the objects of the classes
// that are part of the Bicycle (saddle, wheels) - this is a composition
class Bike
{
  Saddle sd; // one saddle - part that complements the bike
  Wheel whl[2]; // two wheels - part of a bicycle

  // Fields and methods of class Bike
  // ...
};

 


Related topics