Урок 113. Классы. Объекты и методы классов

   ⁄ 

 Обновлено 7 Фев 2018  ⁄ 

⁄   5176

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

Например, структура для хранения даты:

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

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

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

18/11/2018

Классы

В мире объектно-ориентированного программирования типы данных могут не только содержать данные, но и функции, которые будут работать с этими данными. Для определения такого типа данных в C++ используется ключевое слово class. Использование ключевого слова class определяет новый пользовательский тип данных — класс.

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

Единственным существенным отличием здесь является public ключевое слово в классе. О нем мы поговорим детальнее в следующем уроке.

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

В C++, переменная класса называется экземпляром или объектом класса. Точно так же, как определение переменной фундаментального типа данных (например, int x) приводит к выделению памяти для этой переменной, так же и создание объекта класса (например, DateClass today) приводит к выделению памяти для этого объекта.



Методы класса

Помимо хранения данных, классы также могут содержать функции! Функции, определенные внутри класса, называются функциями-членами или методами. Методы могут быть определены внутри или вне класса. Пока что мы будем определять их внутри класса (для простоты), как определить их вне класса – рассмотрим несколько позже.

Класс Date с методом вывода даты:

Точно так же, как к членам структуры, к членам (переменным и функциям) класса доступ осуществляется через оператор выбора членов (.):

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

18/11/2018

Обратите внимание, как эта программа похожа с программой выше (где используется структура).

Однако есть несколько отличий. В версии DateStruct для print() нам нужно было передать переменную структуры непосредственно в функцию print() в качестве параметра. Если бы мы этого не сделали, то print() не знал бы, какую переменную DateStruct выводить. Нам тогда бы пришлось явно ссылаться на члены структуры внутри функции.

Методы класса работают несколько иначе: все вызовы функций-членов должны быть связаны с объектом класса. Когда мы вызываем today.print(), мы сообщаем компилятору вызвать метод print() объекта today.

Рассмотрим определение метода print еще раз:

На что фактически ссылаются m_day, m_month и m_year? Они ссылаются на связанный объект today (который определен caller-ом).

Поэтому, при вызове today.print(), компилятор интерпретирует m_day как today.m_day, m_month как today.m_month и m_year как today.m_year. Если бы мы вызвали tomorrow.print(), то m_day ссылался бы на tomorrow.m_day.

По сути, связанный объект неявно передается функции-члену. По этой причине его часто называют неявным объектом.

Детальнее о том, как передается неявный объект функции-члену, мы поговорим в следующих уроках.

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

Использование префикса «m_» (m = members) для переменных-членов помогает отличать переменные-члены от параметров функции или локальных переменных внутри методов класса. Это полезно по нескольким причинам:

  во-первых, когда мы видим переменную с префиксом «m_», то мы понимаем, что работаем с переменной-членом класса;

  во-вторых, в отличие от параметров функции или локальных переменных, объявленных внутри функции, переменные-члены объявляются в определении класса. Следовательно, если мы хотим знать, как объявлена ​​переменная с префиксом «m_», мы понимаем, что искать нужно в определении класса, а не внутри функции.

Обычно, программисты пишут имена классов с заглавной буквы.

Правило: Пишите имена классов с заглавной буквы.

Вот еще один пример программы с классом:

Результат:

Name: John
Id: 5
Wage: $30

Name: Max
Id: 6
Wage: $32.75

В отличие от обычных функций, порядок, в котором определены методы класса, не имеет значения!



Примечание о структурах в C++

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

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

Правило: Используйте ключевое слово struct для структур, используемых только для хранения данных. Используйте ключевое слово class для объектов, объединяющих как данные, так и функции.

Вы уже использовали классы, не зная об этом

Оказывается, стандартная библиотека C++ полна классов, созданных для вашего удобства. std::string, std::vector и std::array – это всё типы классов! Поэтому, когда вы создаете объект любого из этих типов, вы создаете объект класса. И когда вы вызываете функцию с использованием этих объектов, вы вызываете метод.

Итого

Ключевое слово class позволяет создать пользовательский тип данных в C++, который может содержать как переменные-члены, так и функции-члены. Классы – это основа объектно-ориентированного программирования!

Тест

1. Создайте класс Numbers, который содержит два целых числа. Этот класс должен иметь две переменные-члены для хранения этих двух целых чисел. Вы также должны создать два метода: один с именем «set», который позволит присваивать значения переменным, второй — «print», который будет выводить значения переменных.

Выполнение следующей функции main():

должно производить следующий результат:

Numbers(3, 3)
Numbers(4, 4)

Ответ 1

2. Почему для Numbers должен использоваться класс, а не структура?

Ответ 2

Объект Numbers содержит как переменные-члены, так и функции-члены, поэтому мы должны использовать класс. Мы не должны использовать структуры для объектов, которые имеют функции-члены.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (29 оценок, среднее: 4,90 из 5)
Загрузка...
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

ПОДПИСЫВАЙТЕСЬ

НА КАНАЛ RAVESLI В TELEGRAM

@ravesli

ПОДПИСАТЬСЯ БЕСПЛАТНО