C++. Структуры и наследование. Структуры и полиморфизм. Абстрактная структура. Перегрузка операторов в структурах. Статические методы в структурах

Структуры и наследование. Структуры и полиморфизм. Абстрактная структура. Перегрузка операторов в структурах. Статические методы в структурах

В данной теме на примерах показаны возможности структур в современном C++, которые ничем не уступают классам. Необходимость применения структур в современном C++ состоит в обеспечении совместимости с полезными программами, разработанными в предыдущие годы на языке C. Часто переписывание этих программ заново не имеет смысла, поскольку требует дополнительных временных и человеческих ресурсов.


Содержание


Поиск на других ресурсах:




1. Поддерживают ли структуры наследование? Пример

Да. Структуры поддерживают наследование.

В нижеследующем примере демонстрируется использование унаследованных структур. Базовая структура Worker описывает данные о работнике: имя и возраст. Производная структура WorkerAge содержит методы доступа к полям базовой структуры. Также демонстрируется:

  • доступ из конструктора производной структуры к конструктору базовой структуры;
  • доступ к защищенному (protected) полю базовой структуры из унаследованной структуры;
  • использование указателя this для доступа к полю базовой структуры.

Как видно из примера, в новых версиях C++ структуры есть упрощенным вариантом классов.

#include <iostream>
using namespace std;

// Структура, описывающая данные о работнике - базовая структура
struct Worker
{
private:
  string name; // внутреннее поле, имя работника

public:
  // Конструктор
  Worker(string _name)
  {
    name = _name;
  }

  // Методы доступа к полю name в структуре (геттеры, сеттеры)
  string GetName()
  {
    return name;
  }

  void SetName(string _name)
  {
    name = _name;
  }

protected:
  int age; // защищенное поле - возраст работника
};

// Унаследованная структура от Worker
struct WorkerAge :Worker
{
  // Конструктор с 2 параметрами, вызывает конструктор базовой структуры
  WorkerAge(string _name, int _age) :Worker(_name)
  {
    age = _age;
  }

  // Конструктор с 1 параметром
  WorkerAge(int age) :Worker("Noname")
  {
    this->age = age; // доступ через указатель this на данную структуру
  }

  // Методы доступа к полю age
  int GetAge()
  {
    return age;
  }

  void SetAge(int _age)
  {
    age = _age;
  }
};

void main()
{
  // Методы в структурах

  // 1. Использование структуры Worker
  Worker w(""); // объявить экземпляр структуры, используется конструктор
  w.SetName("John"); // доступ к полю name
  string nm = w.GetName();
  cout << nm.c_str() << endl;

  // 2. Использование структуры WorkerAge
  WorkerAge wa("Micle", 33);
  cout << wa.GetName().c_str() << endl;
  cout << wa.GetAge() << endl;
}

Результат выполнения программы

John
Micle
33

 

2. Может ли структура быть абстрактной?   Поддерживают ли структуры полиморфизм?

Да может. Это означает, что в современных версиях C++ структуры поддерживают полиморфизм.

 

3. Пример, который демонстрирует применение полиморфизма в структурах

Как и классы, структуры поддерживают полиморфизм. В примере демонстрируется применение полиморфизма для структур, которые реализуют наследование.

Объявляется 4 структуры с именами A, B, C, D. Эти структуры образовывают иерархию наследования. Структура A есть базовой для структуры B. Структура B есть базовой для структуры C. Структура C есть базовой для структуры D.

В каждой структуре реализован метод Print(). Структура A есть базовой для структур B, C, D. В этой структуре метод Print() объявлен как чистая виртуальная функция. Такой метод не содержит тела метода. Значит, структура A есть абстрактной. Соответственно синтаксису C++, запрещено объявлять экземпляр структуры A, можно объявлять только указатель или ссылку на эту структуру.

Также в примере реализован метод PrintStruct(), который получает ссылку на базовую структуру A и вызывает виртуальный метод Print().

В функции main() демонстрируется применение полиморфизма в двух аспектах:

  • с использованием указателя на базовую структуру;
  • с использованием ссылки на базовую структуру в методе PrintStruct().

 

#include <iostream>
using namespace std;

// Структура, которая содержит чисто виртуальную функцию - абстрактная структура
struct A
{
  virtual void Print() = 0;
};

// Унаследованные структуры B, C, D
struct B :A
{
  void Print() override
  {
    cout << "B.Print()" << endl;
  }
};

struct C :B
{
  void Print() override
  {
    cout << "C.Print()" << endl;
  }
};

struct D :C
{
  void Print() override
  {
    cout << "D.Print()" << endl;
  }
};

// Метод, получающий ссылку на базовую структуру
// и вызывает метод Print() этой структуры
void PrintStruct(A& refA)
{
  refA.Print(); // вызвать метод Print()
}

void main()
{
  // Демонстрация поддержки полиморфизма в структурах
  // 1. Объявить внутренние переменные
  A* pA;  // указатель на базовую структуру A
  B objB; // экземпляр структуры B
  C objC; // экземпляр структуры C
  D objD; // экземпляр структуры D

  // 1. Вызов метода Print() единым способом (интерфейсом)
  //     с помощью указателя, который указывает на разные экземпляры структур
  pA = &objB; // перенаправить указатель на экземпляр структуры B
  pA->Print(); // вызов B.Print()

  pA = &objC;
  pA->Print(); // вызов C.Print()

  pA = &objD;
  pA->Print(); // вызов D.Print()

  // 2. Передача ссылки на структуру A в метод PrintStruct()
  cout << "-----------------------------------------------------" << endl;

  pA = &objB;
  PrintStruct(*pA);  // вызов B.Print()

  PrintStruct(objB); // вызов B.Print()
  PrintStruct(objC); // вызов C.Print()
  PrintStruct(objD); // вызов D.Print()
}

Результат выполнения программы

B.Print()
C.Print()
D.Print()
-----------------------------------------------------
B.Print()
B.Print()
C.Print()
D.Print()

 

4. Перегрузка операторов в структуре. Структура Point. Пример

В структурах, как и в классах, можно использовать операторные функции, перегружающие операторы. Далее приводится пример структуры Point, в которой реализована перегрузка операторов + (суммирование) и (вычитание).

Структура Point объявляет следующие составляющие:

  • общедоступные (public) переменные x, y, определяющие координаты точки на плоскости;
  • два конструктора, которые инициализируют внутренние переменные;
  • операторную функцию operator+(), которая перегружает оператор + (суммирование);
  • операторную функцию operator–(), которая перегружает оператор (вычитание);
  • метод Print() для вывода информации о точке.

В функции main() демонстрируется использование структуры Point.

#include <iostream>
using namespace std;

// Структура, описывающая точку на координатной плоскости
struct Point
{
public:
  double x, y; // координаты точки

  // Конструкторы
  Point()
  {
    x = y = 0;
  }

  Point(double _x, double _y) : x(_x), y(_y)
  { }

  // Перегруженный оператор +
  Point operator+(Point& pt)
  {
    return Point(x + pt.x, y + pt.y);
  }

  // Перегруженный оператор -
  Point operator-(Point& pt)
  {
    return Point(x - pt.x, y - pt.y);
  }

  // Перегруженный оператор присваивания
  Point operator=(Point pt)
  {
    x = pt.x;
    y = pt.y;
    return *this;
  }

  // Метод вывода информации о точке
  void Print(string objName)
  {
    cout << objName << ": x = " << x << ", y = " << y << endl;
  }
};

void main()
{
  // Демонстрация использования структуры Point
  Point pt1(2, 8.5);
  Point pt2(-5.1, 7.5);

  // Инициализация - тест
  Point pt3 = pt1;
  pt3.Print("pt3");

  // Тест операторной функции operator+()
  Point pt4 = pt1 + pt2;
  pt4.Print("pt4");

  // Тест операторной функции operator=()
  Point pt5;
  pt5 = pt3;
  pt5.Print("pt5");

  // Тест сочетания операторных функций operator-(), operator+()
  Point pt6(1, 1);
  Point pt7(-3, -3);
  cout << "---------------" << endl;
  pt6.Print("pt6");
  pt7.Print("pt7");

  Point pt8 = pt6 - pt7 - pt3 + pt4; // pt8 = (-1.1, 11.5)
  pt8.Print("pt8");
}

 

5. Использование статических методов в структурах. Пример

В структурах могут использоваться статические методы и переменные. В примере реализована структура Complex, которая содержит статические методы вычисления суммы, разности, произведения и деления комплексных чисел. Также в структуре реализован метод Print(), выводящий комплексное число в удобном виде.

В функции main() демонстрируется использование статических методов класса Complex.

Текст демонстрационной программы типа ConsoleApplication следующий:

#include <iostream>
using namespace std;

// Структура, содержащая статические методы обработки комплексных чисел
struct Complex
{
  // Общедоступные статические методы
  // Суммирование комплексных чисел (a1+b1*i) + (a2+b2*i)
  static void Add(double a1, double b1, double a2, double b2,
                  double& a, double& b)
  {
    a = a1 + a2;
    b = b1 + b2;
  }

  // Вычитание комплексных чисел
  static void Sub(double a1, double b1, double a2, double b2,
                  double& a, double& b)
  {
    a = a1 - a2;
    b = b1 - b2;
  }

  // Умножение комплексных чисел
  static void Mul(double a1, double b1, double a2, double b2,
                  double& a, double& b)
  {
    a = a1 * a2 - b1 * b2;
    b = a1 * b2 + b1 * a2;
  }

  // Деление комплексных чисел
  static void Div(double a1, double b1, double a2, double b2,
                  double& a, double& b)
  {
    double denom = a2 * a2 + b2 * b2;

    // Проверка, можно ли корректно разделить два числа
    if (denom == 0)
    {
      a = b = 0; // установить нулевые значения
      return;
    }

    a = (a1 * a2 + b1 * b2) / denom;
    b = (a2 * b1 - a1 * b2) / denom;
  }

  // Вывод информации о комплексном числе
  static void Print(string text, double a, double b)
  {
    // Установить точность 2 знака после запятой
    cout.precision(2);

    cout << text << a;
    if (b > 0)
      cout << "+";
    cout << b << "*i" << endl;
  }
};

void main()
{
  // Статические методы в структуре
  double a1 = 3, b1 = 2.5;
  double a2 = 7, b2 = -1.8;
  double a, b;

  // Вывести первое число
  Complex::Print("z1 = ", a1, b1);

  // Вывести второе число
  Complex::Print("z2 = ", a2, b2);

  // Вычислить сумму, результат в a, b
  Complex::Add(a1, b1, a2, b2, a, b);
  Complex::Print("z1 + z2 = ", a, b);

  // Вычислить разницу
  Complex::Sub(a1, b1, a2, b2, a, b);
  Complex::Print("z1 - z2 = ", a, b);

  // Вычислить произведение
  Complex::Mul(a1, b1, a2, b2, a, b);
  Complex::Print("z1 * z2 = ", a, b);

  // Вычислить деление комплексных чисел
  Complex::Div(a1, b1, a2, b2, a, b);
  Complex::Print("z1 / z2 = ", a, b);
}

Результат выполнения программы:

z1 = 3+2.5*i
z2 = 7-1.8*i
z1 + z2 = 10+0.7*i
z1 - z2 = -4+4.3*i
z1 * z2 = 26+12*i
z1 / z2 = 0.32+0.44*i

 


Связанные темы