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

 


Зв’язані теми