Печатать книгуПечатать книгу

§ 22. Тип данных класс (class)

Сайт: Профильное обучение
Курс: Информатика. 10 класс (Повышенный уровень)
Книга: § 22. Тип данных класс (class)
Напечатано:: Гость
Дата: Четверг, 2 Май 2024, 18:49

22.1. Понятие класса

Язык программирования C++ предоставляет большое количество различных типов и структур данных (например: char, int, double, vector, list и т. д.), которых достаточно для решения относительно простых задач. Однако для решения более сложных проблем функционала этих типов может не хватать.

В С++ есть возможность определять собственные типы данных, которые будут применяться для решения конкретной задачи. Вы уже создавали структуры, которые могут использоваться для создания собственных пользовательских типов данных.

Структуры — это традиционный способ представления сложных типов данных, характерный для парадигмы структурного программирования.

В объектно-ориентированном программировании[1] типы данных могут содержать не только данные, но и функции, которые могут работать с этими данными. Таким типом данных является класс.


[1] С принципами объектно-ориентированного программирования вы познакомитесь в 11-м классе.  

В языке C структуры могут только хранить данные и не могут иметь методов для их обработки. В C++, после проектирования классов (используя ключевое слово class), Бьёрн Страуструп размышлял о том, нужно ли, чтобы структуры (которые были унаследованы из языка С) имели связанные функции-члены. После некоторых размышлений он решил, что нужно. Поэтому сегодня структуры и классы в С++ имеют больше сходства, чем различий.

Многие разработчики считают, что такое решение не было правильным, поскольку оно может привести к реальным проблемам (например, с выделением и очисткой памяти). Поэтому рекомендуется использовать ключевое слово struct для структур, применяемых только для хранения данных, и ключевое слово class для описания объектов, которые требуют объединения данных, и методов их обработки.

22.2. Описание класса

В классе объявляются данные и функции, которые оперируют этими данными (выполняют их обработку).

Каждая переменная типа «класс» является объектом. Объект класса определяется конкретным значением данных (переменных), которое называют состоянием объекта.

Данные, которыми можно характеризовать объект класса, называют полями. Функции, которые могут выполнять какие-либо действия над данными (свойствами) класса, называют методами.

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

Для определения такого типа данных в C++ используется ключевое слово class. В примере 22.1 приведены описания классов (некоторые из примеров использовались для описания структур). В примере 22.2 дано описание объектов соответствующих классов.

Все свойства и методы классов имеют права доступа. По умолчанию все содержимое класса является доступным для чтения и записи только для него самого. Для того чтобы разрешить доступ к данным класса извне, используют модификатор доступа public. Все функции и переменные, которые находятся после модификатора public, становятся доступными из всех частей программы.

Закрытые данные класса размещаются после модификатора доступа private. Если отсутствует модификатор public, то все функции и переменные по умолчанию являются закрытыми.

Обычно приватными делают все свойства класса, а публичными — его методы. Все действия с закрытыми свойствами класса реализуются через его методы.

В общем виде описание класса выглядит следующим образом:

class имя_класса
{
  private:
  /* список свойств и методов для 
  использования внутри класса */
  public:
  /* список методов, доступных другим 
  функциям и объектам программы */
  protected:
  /*список средств, доступных для 
  дружественных классов и наследников*/
};

Поскольку метод в классе является функцией, то и описывают методы так же, как описывают функции.

Объявляют методы внутри класса, а определение методов может быть как внутри класса, так и вне его. Определение методов вне класса позволяет при необходимости легко вынести их в отдельный файл. В промышленной разработке ПО поступают именно таким образом.

Определения методов класса очень похоже на обычные определения функций. Каждый из методов имеет заголовок и тело, может иметь тип возвращаемого значения и параметры. Но есть и отличия:

1. При определении функции как метода класса используется значок «::»[1] для идентификации класса, которому принадлежит функция.

2. Методы класса имеют доступ ко всем приватным компонентам своего класса.

В примере 22.3 приведены описания классов из примера 22.1, дополненные описанием методов.

Поскольку данные в классе являются приватными, пользователь не может напрямую определить или изменить значения данных. Для этих целей используются специальные методы.

В классах принято объявлять так называемые set- и get- функции (в русскоязычной литературе их иногда называют сеттеры и геттеры), с помощью которых можно работать с элементами данных. Таких функций в классе может быть несколько.

В примере 22.4 показано, как можно установить set- и get- функции для класса date. Функции-сеттеры позволяют установить день, месяц или год в дате. Функция-геттер позволяет получить часть даты (день и месяц) в виде строки, в которой день и месяц разделены точкой.

Для начальной инициализации класса используются конструкторы. Конструктор —  специальный тип метода класса, который автоматически вызывается при создании объекта этого же класса. Конструкторы обычно используются для инициализации свойств объекта класса.

В отличие от обычных методов конструкторы имеют определенные правила именования:

  • конструктор должен иметь то же имя, что и класс;
  • конструктор не имеет типа возврата.

В классе может быть несколько конструкторов. Конструктор, который не имеет параметров, называется конструктором по умолчанию. Он вызывается, если пользователем не указаны значения для инициализации. Конструкторы также могут быть объявлены с параметрами, которые используются для инициализации полей. В классе можно определить любое количество конструкторов, каждый из которых должен иметь уникальные параметры.

В примере 22.5 в класс date добавлены три конструктора. Конструктор по умолчанию, который устанавливает дату 01.01.1900; конструктор, который принимает три параметра — день, месяц, год; конструктор с одним параметром — строкой, которая содержит дату, с разделителем «.».

Конструкторы, как и set- и get-функции, обычно объявляются публичными.

В примере 22.5 продемонстрирована работа с классом в функции main.

Деструктор класса — еще один специальный метод — вызывается при уничтожении объекта. Имя деструктора аналогично имени конструктора, только в начале ставится знак тильды: ~. Деструктор не имеет входных параметров. Деструктор всегда один. Для простых классов (тех, которые только инициализируют значения обычных свойств) деструктор не нужен, так как C++ автоматически выполнит очистку памяти самостоятельно. Деструкторы не вызываются явно. Однако их могут безопасно вызывать другие методы класса, т. к. объект не уничтожится до тех пор, пока не выполнится деструктор.


[1] Значок обозначает операцию «раскрытие области видимости».

Сложные типы данных (строка, вектор, список, стек и др.) из STL реализованы как классы. Поэтому, когда вы описываете переменную любого из этих типов, вы создаете объект класса. А когда вы вызываете функцию с использованием этих объектов, вы вызываете метод.

Пример 22.1. Описание классов.

Класс для описания точки на плоскости:

class tchk
{
  double x, y;
};

Класс для описания даты:

class date
{
  int d, m, g;
};

Класс, описывающий студента, поступившего в вуз по результатам ЦТ:

class student

{

  string fam, gorod;

  int god_r;

  vector <int> otm = vector<int>(3);

  int sr_bal;

};

В данном примере для каждого студента хранится его фамилия (fam), город, из которого он приехал (gorod), год рождения (god_r). В векторе otm[1] хранятся три отметки, полученные на ЦТ, поле sr_bal предназначено для хранения среднего балла аттестата.

Пример 22.2. Описание переменных типа класс.

tchk A, B;
date d1, d2;
vector <student> gruppa (30);

Здесь описаны переменные А и В типа tchk (две точки); переменные d1 и d2 типа date (две даты) и переменная gruppa, являющаяся массивом, содержащим описание для 30 студентов.

Главным отличием в описании структуры и класса является то, что при описании структуры по умолчанию все поля и функции являются публичными, но при необходимости их можно сделать приватными. В классе по умолчанию все свойства и методы являются приватными, а публичными их делают при необходимости.

Пример 22.3 Расширение описания классов.

Класс для описания точки на плоскости. Добавлен метод вычисления угла наклона к оси OX отрезка, соединяющего начало координат с точкой.

class tchk

{

  private:

    double x, y;

  public:

    double ugol();

};

 

double tchk::ugol()

{

  double tg = y / x;

  return atan(tg) * 180 / acos(-1);

}

Класс для описания даты. Добавлен метод для вывода даты на экран с разделителем «.»:

class date

{

  private:

   int d, m, g;

  public:

   void print();

};

 

void date::print()

{

  cout << d << "." << m << "." << g;

}

Класс, описывающий студента, поступившего в вуз по результатам ЦТ. Добавлен метод для вычисления суммарного балла отметок:

class student

{

  private:

    string fam, gorod;

    int god_r;

    vector <int> otm = vector<int>(3);

    int sr_ball;

  public:

    int summ();

};

 

int student::summ()

{

   int s = 0;

   for (auto i:otm)

     s += i;

   return s;

}

Пример 22.4 Добавление set- и get-функций к классу date.

class date

{

  private:

    int d, m, g;

  public:

    void print();

    void set_den(int x) {= x;}

    void set_mesjac(int x) {= x;}

    void set_god(int x) {= x;}

    string get_date_dm();

};

 

void date::print()

{

  cout << d << "." << m << "." << g;

}

 

string date::get_date_dm()

{

  string t1 = to_string(d);

  string t2 = to_string(m);

  return t1 + "." + t2;

}

Пример 22.5 Добавление конструкторов к классу date. Демонстрация работы с классом.

Программа:

#include <iostream>

#include <vector>

#include <cmath>

#include <string>

 

using namespace std;

using namespace std::__cxx11;

 

class date

{

  private:

    int d, m, g;

  public:

    date() {= 1; m = 1; g = 1900;}

    date(int t_d, int t_m, int t_g);

    date(string s);

    void print();

    void set_den(int x) {= x;}

    void set_mesjac(int x) {= x;}

    void set_god(int x) {= x;}

    string get_date_dm();

};

 

date::date(int t_d, int t_m, int t_g)

{

  d = t_d;

  m = t_m;

  g = t_g;

}

 

date::date(string s)

{

  d = stoi(s.substr(0,2));

  m = stoi(s.substr(3,2));

  g = stoi(s.substr(6,4));

}

 

void date::print()

{

  cout << d << "." << m << "." << g;

}

 

string date::get_date_dm()

{

  string t1 = to_string(d);

  string t2 = to_string(m);

  return t1 + "." + t2;

}

 

int main()

{

  date d1;

  d1.print();

  cout << endl;

  cout << "tri chisla" << endl;

  int t1, t2, t3;

  cin >> t1 >> t2 >> t3;

  date d2(t1, t2, t3);

  d2.print();

  cout << endl;

  string s = "13.07.2020";

  date d3(s);

  cout << d3.get_date_dm() << endl;

  return 0;

}

Тестирование.

Анализ результатов.

В программе созданы три объекта типа date. Для первого (d1) использовался конструктор по умолчанию. Для второго (d2) использовался конструктор, который инициализировал объект тремя числами, введенными с клавиатуры. Третий объект (d3) инициализирован строкой. Для вывода третьего объекта использован метод get_date_dm, который выводит только число и месяц.


[1] При описании вектора в качестве свойства класса нельзя инициализировать элементы данных сразу в скобках (vector <int> otm(3)), нужно свойству присвоить инициализируемое значение.

22.3. Пример работы с классом

При использовании объектов система программирования Code::Blocks выдает подсказки для полей и методов пользовательских классов, так же как и для встроенных классов.

Для пользовательских классов, объявленных в текущем файле (не вынесенных в отдельный файл), в списке присутствуют и приватные компоненты класса. Приватные компоненты класса помечаются красным, а публичные — зеленым. Кружочек возле компонента класса означает, что он является полем. Кружочек в скобках указывает на метод, значок плюс возле кружочка — на то, что это конструктор.

Пример 22.6. Описать класс IntNumber для работы с целым числом. В классе определить функции для реализации следующих методов: проверки числа на простоту, подсчета количества цифр в числе, «переворота», получение процентов от числа. Продемонстрировать работу методов.

Этапы выполнения задания

I. Исходные данные: переменная s — число.

II. Результат: демонстрация работы методов класса.

III. Алгоритм решения задачи.

1. Ввод исходных данных.
2. 
Реализуем следующие методы.

2.1. Логическая функция simple() проверит, является ли число простым. Проверка числа на простоту была реализована в примере 11.26. 
2.2. Функции kol_numbers() для подсчета количества цифр в числе (реализована в примере 8.17) и переворота числа perevorot() будут возвращать значения int
2.3. Функция percent(double z) для получения процентов от числа будет зависеть от параметра (величина процента) и возвращать тип double.

3. Вывод результатов.

IV. Описание переменных: n – IntNumber, IntNumber – class.

Пример 22.6.

V. Программа:

#include <iostream>

#include <сmath>

 

using namespace std;

 

class IntNumber

{

  int field;

  public:

    //конструктор класса

    IntNumber(int fi) {field = fi;}

    //получение значения числа

    int get_num() {return field;}

  //проверка на простоту

    bool simple();

    //количество цифр числа

    int kol_numbers();

    //переворот числа

    int perevorot();

  //процент от числа

    double percent(double z);

};

 

bool IntNumber::simple()

{

  int i = 2;

    while (field % i != 0 &&

           i * i <= field)

      i++;

    return(* i > field);

}

 

int IntNumber::kol_numbers()

{

  int i = 0;

  int s = field;

  while (> 0){

    i++;

    s /= 10;

  }

  return i;

}

 

int IntNumber::perevorot()

{

  int x = 0;

  int s = field;

    while (>= 1){

      x = x * 10 + s % 10;

      s /= 10;

  }

    return x;

}

 

double IntNumber::percent(double z)

{

  return field * z / 100;

}

 

int main()

{

  int a;

  cout << "vvedi chislo" << endl;

  cin >> a;

  IntNumber n(a);

  if (n.simple()){

    cout << "chislo " << n.get_num();

    cout << " - prostoe" << endl;

  }

  else {

    cout << "chislo " << n.get_num();

    cout << " - sostavnoe" << endl;

  }

  cout << "v chisle " << n.get_num();

  cout << " kol-vo cifr = " ;

  cout << n.kol_numbers() << endl;

  cout << "perevertysh chisla - ";

  cout << n.perevorot() << endl;

  double x;

  cout << "vvedi %" << endl;

  cin >> x;

  cout << x << "% ot chisla ";

  cout << n.get_num() << " - ";

  cout << n.percent(x) << endl;

  return 0;

}

VI. Тестирование.

Вопросы к параграфу

1. Что такое класс?

2. Для чего предназначены поля и методы класса?

3. Какие специальные методы используются для получения доступа к свойствам класса?

4. Зачем используется конструктор?

Упражнения

    

1. Дополните класс date (пример 22.5) перечисленными возможностями.

    1. Метод для получения количества дней в месяце.
    2. Метод для проверки, является ли год високосным.
    3. Метод для проверки корректности даты.
    4. Метод для получения номера текущего дня при отсчете от 1.1.1900. (см. пример 16.13).
    5. Конструктор с двумя параметрами, которые являются числом и месяцем, для года установить текущий.
    6. Предложите свои функции.

2. Дополните класс IntNumber (пример 22.6) перечисленными возможностями.

1. Метод для проверки числа на то, является ли оно полным квадратом.
2. 
Метод для вычисления факториала числа.
3. 
Метод для проверки числа на то, является ли оно «именным»:

    • простым числом Мерсена (число Мерсена представимо в виде 2n – 1);
    • числом Армстронга (натуральное число из k цифр является числом Армстронга, если сумма его цифр, возведенных в k-ю степень, равна самому числу, например 153 = 13 + 53 + 33, k = 3);
    • другим интересным числом (см. упр. 6 после § 8)

4. Метод для разложения числа на простые множители.
5. Предложите свои функции.

3. Реализуйте класс для хранения времени. Добавьте в качестве методов те функции, которые были реализованы для соответствующей структуры (пример 16.12).

4. Создайте класс treugolnik1, реализующий математические формулы для вычисления площади треугольника, периметра треугольника, средней линии, радиусов вписанной и описанной окружностей и др.