Класс (программирование): различия между версиями

Материал из Поле цифровой дидактики
м (1 версия импортирована)
 
Строка 1: Строка 1:
{{другие значения|Класс}}
'''Класс''' — в [[Объектно-ориентированное программирование|объектно-ориентированном программировании]], ''модель'' для создания [[Объект (программирование)|объектов]] определённого [[Тип данных|типа]], описывающая их структуру (набор полей и их начальное состояние) и определяющая алгоритмы (функции или [[Метод (программирование)|методы]]) для работы с этими объектами.  
'''Класс''' — в [[Объектно-ориентированное программирование|объектно-ориентированном программировании]], ''модель'' для создания [[Объект (программирование)|объектов]] определённого [[Тип данных|типа]], описывающая их структуру (набор полей и их начальное состояние) и определяющая алгоритмы (функции или [[Метод (программирование)|методы]]) для работы с этими объектами.  


Иными словами, класс служит средством для введения [[Абстрактный тип данных|абстрактных типов данных]] в программный проект. Другие ''описатели'' абстрактных типов данных — [[Метакласс|метаклассы]], [[Интерфейс (объектно-ориентированное программирование)|интерфейсы]], [[Структура (программирование)|структуры]], [[Перечисляемый тип|перечисления]], — характеризуются какими-то своими особенностями.
 
Суть отличия классов состоит в том, что при задании типа данных, класс определяет одновременно как интерфейс, так и реализацию для всех своих экземпляров (т.е. объектов), поэтому вызов метода-конструктора обязателен.
Суть отличия классов состоит в том, что при задании типа данных, класс определяет одновременно как интерфейс, так и реализацию для всех своих экземпляров (т.е. объектов), поэтому вызов метода-конструктора обязателен.


'''Класс является одним из ключевых понятий в ООП''', но существуют и бесклассовые объектно-ориентированные языки, например, [[Self]], [[JavaScript]], [[Lua]], (подробнее смотрите [[Прототипное программирование]]).
'''Класс является одним из ключевых понятий в ООП''', но существуют и бесклассовые объектно-ориентированные языки, например, [[Self]], [[JavaScript]], [[Lua]],  


На практике [[объектно-ориентированное программирование]] сводится к созданию некоторого количества классов, включая интерфейс и реализацию, и последующему их использованию. Графическое представление некоторого количества классов и связей между ними называется [[Диаграмма классов|диаграммой классов]]. Объектно-ориентированный подход за время своего развития накопил множество рекомендаций ([[Шаблоны проектирования|паттернов]]) по созданию классов и [[Иерархия классов|иерархий классов]].
На практике [[объектно-ориентированное программирование]] сводится к созданию некоторого количества классов, включая интерфейс и реализацию, и последующему их использованию. Графическое представление некоторого количества классов и связей между ними называется [[Диаграмма классов|диаграммой классов]].  


Идея классов пришла из работ по [[База знаний|базам знаний]], имеющих отношение к исследованиям по искусственному интеллекту. Используемые человеком классификации в зоологии, ботанике, химии, деталях машин, несут в себе основную идею, что любую вещь всегда можно представить частным случаем некоторого более общего понятия. Конкретное яблоко — это в целом некоторое яблоко, вообще яблоко, а любое вообще яблоко — фрукт. (Яблоки и груши - частый пример классов в учебных пособиях по объектно-ориентированному программированию.)
Идея классов пришла из работ по [[База знаний|базам знаний]], имеющих отношение к исследованиям по искусственному интеллекту. Используемые человеком классификации в зоологии, ботанике, химии, деталях машин, несут в себе основную идею, что любую вещь всегда можно представить частным случаем некоторого более общего понятия. Конкретное яблоко — это в целом некоторое яблоко, вообще яблоко, а любое вообще яблоко — фрукт. (Яблоки и груши - частый пример классов в учебных пособиях по объектно-ориентированному программированию.)
Строка 20: Строка 19:
При использовании классов все элементы кода программы, такие как переменные, константы, методы, процедуры и функции, могут принадлежать (а во многих языках обязаны принадлежать) тому или иному классу. Сам класс в итоге определяется как список своих ''членов'', а именно [[поле класса|полей]] ([[свойство (программирование)|свойств]]) и [[Функция (программирование)|методов/функций/процедур]]. В зависимости от языка программирования к этому списку могут добавиться константы, атрибуты и внешние определения.
При использовании классов все элементы кода программы, такие как переменные, константы, методы, процедуры и функции, могут принадлежать (а во многих языках обязаны принадлежать) тому или иному классу. Сам класс в итоге определяется как список своих ''членов'', а именно [[поле класса|полей]] ([[свойство (программирование)|свойств]]) и [[Функция (программирование)|методов/функций/процедур]]. В зависимости от языка программирования к этому списку могут добавиться константы, атрибуты и внешние определения.


Как и структуры, классы могут задавать поля — то есть переменные, принадлежащие либо непосредственно самому классу (статические), либо экземплярам класса (обычные). Статические поля существуют в одном экземпляре на всю программу (или, в более сложном варианте, — в одном экземпляре на [[Процесс (информатика)|процесс]] или на [[Многопоточность|поток/нить]]). Обычные поля создаются по одной копии для каждого конкретного объекта — экземпляра класса. Например, общее количество строк текста, созданных в программе за время её работы, будет являться статическим полем класса «строка текста». А конкретный массив символов строки будет являться обычным полем экземпляра класса «строка текста», так же как переменная «фамилия», имеющая тип «строка текста», будет являться обычным полем каждого конкретного экземпляра класса «человек».
Обычные поля создаются по одной копии для каждого конкретного объекта — экземпляра класса. Например, общее количество строк текста, созданных в программе за время её работы, будет являться статическим полем класса «строка текста». А конкретный массив символов строки будет являться обычным полем экземпляра класса «строка текста», так же как переменная «фамилия», имеющая тип «строка текста», будет являться обычным полем каждого конкретного экземпляра класса «человек».
 
В ООП при использовании классов весь исполняемый код программы (алгоритмы) будет оформляться в виде так называемых «методов», «функций» или «процедур», что соответствует обычному [[Структурное программирование|структурному программированию]], однако теперь они могут (а во многих языках обязаны) принадлежать тому или иному классу. Например, по возможности, класс «строка текста» будет содержать все основные методы/функции/процедуры, предназначенные для работы со строкой текста, такие как поиск в строке, вырезание части строки и т. д.


Как и поля, код в виде методов/функций/процедур, принадлежащих классу, может быть отнесен либо к самому классу, либо к экземплярам класса. Метод, принадлежащий классу и соотнесенный с классом (статический метод) может быть вызван сам по себе и имеет доступ к статическим переменным класса. Метод, соотнесенный с экземпляром класса (обычный метод), может быть вызван только у самого объекта, и имеет доступ как к статическим полям класса, так и к обычным полям конкретного объекта (при вызове этот объект передастся скрытым параметром метода). Например, общее количество созданных строк можно узнать из любого места программы, но длину конкретной строки можно узнать только указав, тем или иным образом, длину какой строки будем мерить.
Как и поля, код в виде методов/функций/процедур, принадлежащих классу, может быть отнесен либо к самому классу, либо к экземплярам класса. Метод, принадлежащий классу и соотнесенный с классом (статический метод) может быть вызван сам по себе и имеет доступ к статическим переменным класса. Метод, соотнесенный с экземпляром класса (обычный метод), может быть вызван только у самого объекта, и имеет доступ как к статическим полям класса, так и к обычным полям конкретного объекта (при вызове этот объект передастся скрытым параметром метода). Например, общее количество созданных строк можно узнать из любого места программы, но длину конкретной строки можно узнать только указав, тем или иным образом, длину какой строки будем мерить.
Строка 28: Строка 25:
== Интерфейс и реализация, наследование реализации ==
== Интерфейс и реализация, наследование реализации ==
В программировании есть понятие программного интерфейса, означающего перечень возможных вычислений, которые может выполнить та или иная часть программы. Это включает описание: какие аргументы и в каком порядке требуется передавать на вход алгоритмам из перечня, а также что и в каком виде они будут возвращать. Абстрактный тип данных [[Интерфейс (объектно-ориентированное программирование)|интерфейс]] придуман для формализованного описания такого перечня. Сами алгоритмы, то есть действительный программный код, который будет выполнять все эти вычисления, интерфейсом ''не'' задаётся, программируется отдельно и называется ''реализацией интерфейса''.
В программировании есть понятие программного интерфейса, означающего перечень возможных вычислений, которые может выполнить та или иная часть программы. Это включает описание: какие аргументы и в каком порядке требуется передавать на вход алгоритмам из перечня, а также что и в каком виде они будут возвращать. Абстрактный тип данных [[Интерфейс (объектно-ориентированное программирование)|интерфейс]] придуман для формализованного описания такого перечня. Сами алгоритмы, то есть действительный программный код, который будет выполнять все эти вычисления, интерфейсом ''не'' задаётся, программируется отдельно и называется ''реализацией интерфейса''.
Программные интерфейсы, а также классы, могут расширяться путём [[Наследование (программирование)|наследования]], которое является одним из важных средств повторного использования готового кода в ООП. Наследованный класс или интерфейс будет содержать в себе всё, что указано для всех его родительских классов (в зависимости от языка программирования и платформы, их может быть от нуля до бесконечности). Например, можно создать свой вариант текстовой строки путём наследования класса «моя строка текста» от уже существующего класса «строка текста», при этом предполагается, что программисту не придется заново переписывать алгоритмы поиска и прочее, так как они автоматически будут унаследованы от готового класса, и любой экземпляр класса «моя строка текста» может быть передан не только в готовые методы родительского класса «строка текста» для проведения нужных вычислений, но и вообще в любой алгоритм, способный работать с объектами типа «строка текста», так как экземпляры обоих классов совместимы по программным интерфейсам.


Класс позволяет задать не только программный интерфейс к самому себе и к своим экземплярам, но и в явном виде написать код, ответственный за вычисления. Если при создании своего нового типа данных наследовать интерфейс, то мы получим возможность передавать экземпляр своего типа данных в любой алгоритм, который умеет работать с этим интерфейсом. Однако нам придется самим написать реализацию интерфейса, то есть те алгоритмы, которыми будет пользоваться интересующий нас алгоритм для проведения вычислений с использованием нашего экземпляра. В то же время, наследуя класс, мы автоматически наследуем готовый код под интерфейс (это не всегда так, родительский класс может требовать реализации каких-то алгоритмов в дочернем классе в обязательном порядке). В этой возможности наследовать готовый код и проявляется то, что в объектно-ориентированной программе тип данных ''класс'' определяет одновременно и интерфейс, и реализацию для всех своих экземпляров.
Класс позволяет задать не только программный интерфейс к самому себе и к своим экземплярам, но и в явном виде написать код, ответственный за вычисления. Если при создании своего нового типа данных наследовать интерфейс, то мы получим возможность передавать экземпляр своего типа данных в любой алгоритм, который умеет работать с этим интерфейсом. Однако нам придется самим написать реализацию интерфейса, то есть те алгоритмы, которыми будет пользоваться интересующий нас алгоритм для проведения вычислений с использованием нашего экземпляра. В то же время, наследуя класс, мы автоматически наследуем готовый код под интерфейс (это не всегда так, родительский класс может требовать реализации каких-то алгоритмов в дочернем классе в обязательном порядке). В этой возможности наследовать готовый код и проявляется то, что в объектно-ориентированной программе тип данных ''класс'' определяет одновременно и интерфейс, и реализацию для всех своих экземпляров.
Строка 35: Строка 30:
== Состояние объекта, понятие областей доступа, конструкторы ==
== Состояние объекта, понятие областей доступа, конструкторы ==
Одной из проблем структурного программирования, с которой борется ООП, является проблема поддержания правильного значения переменных программы. Часто разные переменные программы хранят логически связанные значения, и за поддержание этой логической связности несет ответственность программист, то есть автоматически связность не поддерживается. Примером могут служить флажки «уволен» и «ожидает премии по итогам года», когда по правилам отдела кадров человек может быть одновременно не уволенным и не ожидающим премии, не уволенным и ожидающим премии, уволенным и не ожидающим премии, но не может быть одновременно и уволенным, и ожидающим премии. То есть любая часть программы, которая проставляет флажок «уволен», всегда должна снимать флажок «ожидает премии по итогам года».
Одной из проблем структурного программирования, с которой борется ООП, является проблема поддержания правильного значения переменных программы. Часто разные переменные программы хранят логически связанные значения, и за поддержание этой логической связности несет ответственность программист, то есть автоматически связность не поддерживается. Примером могут служить флажки «уволен» и «ожидает премии по итогам года», когда по правилам отдела кадров человек может быть одновременно не уволенным и не ожидающим премии, не уволенным и ожидающим премии, уволенным и не ожидающим премии, но не может быть одновременно и уволенным, и ожидающим премии. То есть любая часть программы, которая проставляет флажок «уволен», всегда должна снимать флажок «ожидает премии по итогам года».
Хороший способ решить эту проблему — объявить флажок «уволен» недоступным к изменению для всех участков программы, кроме одного специально оговоренного. В этом специально оговоренном участке всё будет написано один раз и правильно, а все остальные должны будут обращаться к этому участку всегда, когда они хотят установить или снять флажок «уволен».
В объектно-ориентированной программе флажок «уволен» будет объявлен приватным членом некоторого класса, а для чтения и изменения его будут написаны соответствующие публичные методы. Правила, определяющие возможность или невозможность напрямую изменять какие-либо переменные, называются правилами задания областей доступа. Слова «приватный» и «публичный» в данном случае являются так называемыми «''модификаторами доступа''». Они называются ''модификаторами'' потому, что в некоторых языках они используются для изменения ранее установленных прав при наследовании класса. Совместно классы и модификаторы доступа задают область доступа, то есть у каждого участка кода, в зависимости от того, какому классу он принадлежит, будет своя область доступа относительно тех или иных элементов (членов) своего класса и других классов, включая переменные, методы, функции, константы и т. д. Существует основное правило: ничто в одном классе не может видеть приватных элементов другого класса. Относительно других, более сложных правил, в различных языках существуют другие модификаторы доступа и правила их взаимодействия с классами.
Почти каждому члену класса можно установить модификатор доступа (за исключением статических конструкторов и некоторых других вещей). В большинстве [[объектно-ориентированный язык программирования|объектно-ориентированных языков программирования]] поддерживаются следующие модификаторы доступа:
* '''private''' (закрытый, внутренний член класса) — обращения к члену допускаются только из [[Функция (программирование)|методов]] того класса, в котором этот член определён. Любые наследники класса уже не смогут получить доступ к этому члену. Наследование по типу private делает все члены родительского класса (в том числе public и protected) private-членами класса-наследника (С++);
* '''protected''' (защищённый, внутренний член иерархии классов) — обращения к члену допускаются из методов того класса, в котором этот член определён, а также из любых методов его классов-наследников. Наследование по типу protected делает все public-члены родительского класса protected-членами класса-наследника (С++);
* '''public''' (открытый член класса) — обращения к члену допускаются из любой части кода. Наследование по типу public не меняет модификаторов родительского класса (С++);
Проблема поддержания правильного состояния переменных актуальна и для самого первого момента выставления начальных значений. Для этого в классах предусмотрены специальные методы/функции, называемые конструкторами. Ни один объект (экземпляр класса) не может быть создан иначе, как путём вызова на исполнение кода конструктора, который вернет вызывающей стороне созданный и правильно заполненный экземпляр класса. Во многих языках программирования тип данных «структура», как и класс, может содержать переменные и методы, но экземпляры структур, оставаясь просто размеченным участком оперативной памяти, могут создаваться в обход конструкторов, что запрещено для экземпляров классов (за исключением специальных исключительных методов обхода всех подобных правил ООП, предусмотренных в некоторых языках и платформах). В этом проявляется отличие классов от других типов данных — вызов конструктора обязателен.


== Практический подход ==
== Практический подход ==
В современных [[Объектно-ориентированный язык программирования|объектно-ориентированных языках программирования]] (в том числе в [[php]], [[Java]], [[C++]], [[Оберон (язык программирования)|Oberon]], [[Python]], [[Ruby]], [[Smalltalk]], [[Object Pascal]]) создание класса сводится к написанию некоторой структуры, содержащей набор полей и методов (среди последних особую роль играют конструкторы, деструкторы, финализаторы). Практически класс может пониматься как некий шаблон, по которому создаются объекты — экземпляры данного класса. Все экземпляры одного класса созданы по одному шаблону, поэтому имеют один и тот же набор полей и методов.
В современных [[Объектно-ориентированный язык программирования|объектно-ориентированных языках программирования]] (в том числе в [[php]], [[Java]], [[C++]], [[Oberon]], [[Python]], [[Ruby]], [[Smalltalk]], [[Object Pascal]]) создание класса сводится к написанию некоторой структуры, содержащей набор полей и методов (среди последних особую роль играют конструкторы, деструкторы, финализаторы). Практически класс может пониматься как некий шаблон, по которому создаются объекты — экземпляры данного класса. Все экземпляры одного класса созданы по одному шаблону, поэтому имеют один и тот же набор полей и методов.
 
== Отношения между классами ==
* [[Наследование (программирование)|Наследование]] (Генерализация) — объекты дочернего класса наследуют все свойства родительского класса.
* Ассоциация — объекты классов вступают во взаимодействие между собой.
* [[Агрегирование (программирование)|Агрегация]] — объекты одного класса входят в объекты другого.
* Композиция — объекты одного класса входят в объекты другого и зависят друг от друга по времени жизни.
* Класс-[[Метакласс]] — отношение, при котором экземплярами одного класса являются другие классы.


== Виды классов ==
{{Смотри также|Наследование (программирование)}}
* [[Суперкласс (информатика)|Базовый (родительский) класс]]
* [[Подкласс (информатика)|Производный класс (наследник, потомок)]]
* [[Абстрактный класс]]
* [[Интерфейс (объектно-ориентированное программирование)|Интерфейс]]


== Область видимости ==
[[Область видимости]] членов класса (то есть область кода, из которой к ним можно обращаться по неквалифицированному имени — без указания имени класса или объекта) не зависит от их области доступа, и всегда совпадает с кодом методов класса.
Область видимости самого класса по-разному определяется в разных языках программирования. В одних языках (таких как [[Delphi (язык программирования)|Delphi]]) все классы имеют глобальную видимость (с учётом видимости [[модуль (программирование)|модуля]]), в других (таких как [[Java]]) область видимости класса связана с содержащей его единицей компиляции (в Java — с ''пакетом''), в третьих (таких как [[C++]] и [[C Sharp|C#]]) область видимости класса определяется [[Пространство имён (программирование)|пространствами имён]] (''namespaces''), которые задаются программистом явно и могут совпадать или не совпадать с единицами компиляции.
== Классы в языке Object Pascal (среда Delphi) ==
На языке [[Delphi (язык программирования)|Delphi]] класс описывается следующим образом:
<source lang="delphi">
  TMyClass = class(TObject)
  private
    {Описанные в этой секции элементы не доступны извне (за пределами класса, но доступны в пределах модуля).}
    {Здесь обычно находятся поля класса.}
  strict private
    {Для версии Delphi 2007 и выше. Описанные в этой секции элементы доступны только внутри класса}
  protected
    {Описанные в этой секции элементы доступны только классу и всем его потомкам.}
  public
    {Описанные в этой секции элементы доступны всем.}
  published
    {Описанные в этой секции элементы доступны всем и отображаются в Object Inspector'e.}
  end;
</source>
* <code>TMyClass</code> — имя класса;
* <code>class</code> — ключевое слово, начинающее определение класса (в старых версиях также было ключевое слово <code>object</code>);
* <code>TObject</code> — класс-предок, если есть [[Наследование (программирование)|наследование]];
* <code>private, protected, public, published</code> — ключевые слова, определяющие иерархический доступ к полям и методам в виде обозначения секций [[область доступа|областей доступа]].
Создается [[Объект (программирование)|экземпляр]] (объект) класса так:
<source lang="delphi">
  MyClass := TMyClass.Create;
</source>
Уничтожается так:
<source lang="delphi">
  FreeAndNil(MyClass);
ИЛИ
  MyClass.Free;
</source>
== Классы в языке C++ ==
Класс в языке [[C++]] создаётся следующим образом:
<source lang="cpp">
  class MyClass: public ParentClass // ParentClass — класс-предок, если таковой имеется
  {
      public:
        // элементы в этой секции доступны из любой части программы
        MyClass(); // конструктор
        ~MyClass(); // деструктор
      protected:
        // элементы в этой секции доступны из класса и его потомков
      private:
        // элементы в этой секции доступны только из класса; это область доступа по умолчанию
  };
</source>
После своего создания класс считается полноценным [[Тип данных|типом данных]] и, следовательно экземпляры класса создаются следующим образом:
<source lang="cpp">
  MyClass myinstance;
</source>
Обращение к членам класса:
<source lang="cpp">
  myinstance.classmember
</source>
Уничтожается экземпляр класса, как и любая переменная, только в случае, если [[Функция (программирование)|функция]], в которой он был создан, завершила работу или если была принудительно освобождена [[Динамически распределяемая память|динамическая память]], выделенная под класс.
== Классы в языке [[C Sharp|C#]] ==
Классы в языке C# определяются следующим образом:
<source lang="csharp">
public class MyClass
{
  //Член, доступный любому классу программы
  public int k;
  //Член, доступный любому классу в том же модуле программы
  internal int l;
  //Член, доступный любому классу в том же модуле программы либо только текущему классу и всем его подклассам в другом модуле
  protected internal int m;
  //Член, доступный только текущему классу и всем его подклассам
  protected int n;
  //Член, доступный только из текущего класса (по умолчанию).
  private int fg;
}
</source>
В отличие от C++ модификаторы доступа должны указываться для каждого члена в отдельности. Анонимные классы можно определить в методе, например, так:
<source lang="csharp">
public void DoSomething()
{
    var person = new
        {
        Name = "Маргарита";
        Age = 15;
        }
    var pet = new
        {
          Name = "Дуня";
          Type = "Черепаха";
          Owner = person;
        }
    Console.WriteLine("Age of pet owner: " + pet.Owner.Age);
}
</source>


== Классы в языке [[Ruby]] ==
== Классы в языке [[Ruby]] ==
Классы в языке Ruby определяются следующим образом:
Классы в языке Ruby определяются следующим образом:
<source lang="ruby">
 
<syntaxhighlight lang="ruby" line>
class MyClass
class MyClass
   def initialize
   def initialize
Строка 194: Строка 63:
   end
   end
end
end
</source>
</syntaxhighlight>
 
Создание экземпляра класса:
Создание экземпляра класса:
<source lang="ruby">
<syntaxhighlight lang="ruby" line>
object = MyClass.new
object = MyClass.new
</source>
</syntaxhighlight>
Уничтожение экземпляра класса не требуется: оно происходит автоматически с помощью «сборщика мусора», как только из памяти исчезет последняя ссылка на него.
Уничтожение экземпляра класса не требуется: оно происходит автоматически с помощью «сборщика мусора», как только из памяти исчезет последняя ссылка на него.


== Классы в языке Python ==
== Классы в языке Python ==
Определение класса на языке [[Python]] с помощью оператора <code>class</code>:
Определение класса на языке [[Python]] с помощью оператора <code>class</code>:
<source lang="Python">
<syntaxhighlight lang="Python" line>
 
class MyClass:
class MyClass:
       def __init__(self, arg):
       def __init__(self, arg):
Строка 225: Строка 96:
       def method4(cls, arg1, arg2, ...):
       def method4(cls, arg1, arg2, ...):
           """метод класса, доступный для вызова как из экземпляров класса, так и из самого класса, с доступом к внутренним методам и параметрам"""
           """метод класса, доступный для вызова как из экземпляров класса, так и из самого класса, с доступом к внутренним методам и параметрам"""
</source>
</syntaxhighlight>
Создание экземпляра класса:
Создание экземпляра класса:
<source lang="Python">
<syntaxhighlight lang="Python" line>
myinstance = MyClass(4)
myinstance = MyClass(4)
</source>
</syntaxhighlight>
Уничтожение экземпляра класса в явном виде не требуется, так как в Python присутствует автоматический «сборщик мусора». Однако в явном виде удалить ссылку на объект (экземпляр класса или сам класс) можно так:
Уничтожение экземпляра класса в явном виде не требуется, так как в Python присутствует автоматический «сборщик мусора». Однако в явном виде удалить ссылку на объект (экземпляр класса или сам класс) можно так:
<source lang="Python">
<syntaxhighlight lang="Python" line>
del myinstance
del myinstance
</source>
</syntaxhighlight>


== Классы в языке JavaScript ==
== Классы в языке JavaScript ==
Определение класса на языке [[JavaScript]] с помощью оператора <code>class</code>:
Определение класса на языке [[JavaScript]] с помощью оператора <code>class</code>:
<source lang="JavaScript">
<syntaxhighlight lang="JavaScript" line>
 
class MyClass {
class MyClass {
     constructor(arg1, arg2, ...) {
     constructor(arg1, arg2, ...) {
Строка 253: Строка 125:
     }
     }
}
}
</source>
</syntaxhighlight>
Создание экземпляра класса:
<source lang="JavaScript">
var myinstance = new MyClass(4, 2)
</source>
Уничтожение экземпляра класса не требуется: оно происходит автоматически с помощью «сборщика мусора», как только из памяти исчезнет последняя ссылка на него.
 
== Классы в языке Java ==
Каждый класс в Java как правило создается в отдельном файле, имя файла должно соответствовать названию класса. В данном случае это будет MyClass.java
 
Определение класса на языке [[Java]] с помощью оператора <code>class</code>:
 
<br />
<source lang="Java">
  class MyClass {
      String name = "Example";
     
      // "Конструктор"
      public MyClass(String name) {
          this.name = name;
      }
     
      // "Метод"
      public String getName() {
          return name;
      }
  }
</source>
 
Создание экземпляра класса:
<source lang="Java">
  MyClass my = new MyClass("Example 2");
</source>
 
Уничтожение экземпляра класса происходит с помощью «сборщика мусора» автоматически.
 
== Ссылки ==
* [http://java.sun.com/docs/books/tutorial/java/javaOO/classes.html Creating Classes] {{Wayback|url=http://java.sun.com/docs/books/tutorial/java/javaOO/classes.html |date=20051215141223 }} — Руководство по созданию классов в языке Java
 
{{нет источников|дата=2014-10-01}}
{{rq|check}}
{{Типы данных}}


[[Категория:Объектно-ориентированное программирование]]
[[Категория:Статьи с примерами кода Python]]
[[Категория:Структуры данных]]
[[Категория:Структуры данных]]
[[Категория:Статьи с примерами кода C++]]
[[Категория:Статьи с примерами кода Java]]
[[Категория:Статьи с примерами кода Ruby]]
[[Категория:Статьи с примерами кода Object Pascal]]
[[Категория:Статьи с примерами кода C Sharp]]
[[Категория:Концепции языков программирования]]

Текущая версия на 12:00, 19 октября 2022

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


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

Класс является одним из ключевых понятий в ООП, но существуют и бесклассовые объектно-ориентированные языки, например, Self, JavaScript, Lua,

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

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

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

Классы и объекты, понятие экземпляра класса, понятие членов класса

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

Например, абстрактный тип данных «строка текста» может быть оформлен в виде класса, и тогда все строки текста в программе будут являться объектами — экземплярами класса «строка текста».

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

Обычные поля создаются по одной копии для каждого конкретного объекта — экземпляра класса. Например, общее количество строк текста, созданных в программе за время её работы, будет являться статическим полем класса «строка текста». А конкретный массив символов строки будет являться обычным полем экземпляра класса «строка текста», так же как переменная «фамилия», имеющая тип «строка текста», будет являться обычным полем каждого конкретного экземпляра класса «человек».

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

Интерфейс и реализация, наследование реализации

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

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

Состояние объекта, понятие областей доступа, конструкторы

Одной из проблем структурного программирования, с которой борется ООП, является проблема поддержания правильного значения переменных программы. Часто разные переменные программы хранят логически связанные значения, и за поддержание этой логической связности несет ответственность программист, то есть автоматически связность не поддерживается. Примером могут служить флажки «уволен» и «ожидает премии по итогам года», когда по правилам отдела кадров человек может быть одновременно не уволенным и не ожидающим премии, не уволенным и ожидающим премии, уволенным и не ожидающим премии, но не может быть одновременно и уволенным, и ожидающим премии. То есть любая часть программы, которая проставляет флажок «уволен», всегда должна снимать флажок «ожидает премии по итогам года».

Практический подход

В современных объектно-ориентированных языках программирования (в том числе в php, Java, C++, Oberon, Python, Ruby, Smalltalk, Object Pascal) создание класса сводится к написанию некоторой структуры, содержащей набор полей и методов (среди последних особую роль играют конструкторы, деструкторы, финализаторы). Практически класс может пониматься как некий шаблон, по которому создаются объекты — экземпляры данного класса. Все экземпляры одного класса созданы по одному шаблону, поэтому имеют один и тот же набор полей и методов.


Классы в языке Ruby

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

class MyClass
  def initialize
    # Конструктор (необязателен)
  end
  
  public # Идентификатор public необязателен, т.к. установлен по умолчанию,
         # указывает на то, что следующие за ним методы доступны из любого места программы
  def public_method
    # Публичный метод
  end
  
  protected # Идентификатор protected указывает на то, что следующие за ним методы
            # будут доступны только членам данного и дочерних классов
  def protected_method
    # Защищённый метод
  end
  
  private # Идентификатор private указывает на то, что следующие за ним методы
          # будут доступны только членам данного класса
  def private_method
    # Приватный метод
  end
end

Создание экземпляра класса:

object = MyClass.new

Уничтожение экземпляра класса не требуется: оно происходит автоматически с помощью «сборщика мусора», как только из памяти исчезет последняя ссылка на него.

Классы в языке Python

Определение класса на языке Python с помощью оператора class:

class MyClass:
      def __init__(self, arg):
          """Конструктор"""
          self._arg = arg    # параметр объекта

      def method1(self, x):
          """метод, входящий в интерфейс класса"""

      def _method2(self, x):
          """метод, не входящий в интерфейс класса"""

      def __method2(self, x):
          """метод доступный только внутри класса"""

      @staticmethod
      def method3(arg1, arg2, ...):
          """статический метод, доступный для вызова как из экземпляров класса, так и из самого класса"""

      @classmethod
      def method4(cls, arg1, arg2, ...):
          """метод класса, доступный для вызова как из экземпляров класса, так и из самого класса, с доступом к внутренним методам и параметрам"""

Создание экземпляра класса:

myinstance = MyClass(4)

Уничтожение экземпляра класса в явном виде не требуется, так как в Python присутствует автоматический «сборщик мусора». Однако в явном виде удалить ссылку на объект (экземпляр класса или сам класс) можно так:

del myinstance

Классы в языке JavaScript

Определение класса на языке JavaScript с помощью оператора class:

class MyClass {
    constructor(arg1, arg2, ...) {
        //конструктор (необязателен)
        this.arg1 = arg1;
        this.arg2 = arg2;
    }

    method1() {
        // Обычный метод
    }

    static method {
        // Статический метод
    }
}