Понятие класса в C#
Один и тот же субъект материального мира часто рассматривают с точки зрения поставленной задачи, для решения которой требуется информация, описывающая субъект, и соответствующая обработка. В повседневной жизни один и тот же человек может быть пассажиром, покупателем, продавцом, свидетелем, студентом и т. д. Такое наименование указывает, с какой точки зрения в данной конкретной ситуации рассматривается человек, другими словами, применительно к нему предполагается решать задачу, указанную наименованием. Если это пассажир, то требуется информация о виде транспорта, пунктах отправления и прибытия, качестве места, времени отправления и т. д. По отношению к студенту эта информация может быть о фамилии, группе, курсу, успеваемости и т. п. Любая такая информация может быть описана с помощью таблицы. Но представлена она может быть не только в виде таблицы, но также и как диаграмма или как видео клип.
Суть объектно-ориентированного программирования заключается в объединении в единый объект данных и подпрограмм для решения поставленной задачи. При такой концепции изменяется подход к программированию, поскольку обеспечивается жесткая связь данных с программами для их обработки.
Для описания объектов вводится понятие класса. Класс группирует и содержит как данные, описывающие объект, так и подпрограммы, необходимые для обработки этих данных. Каждый класс описывает в общем виде некоторый объект или часть объекта, но объектов такого типа может быть сколь угодно много. Можно представить, что класс описывает строку некоторой таблицы, причем элементы строки могут быть разных типов: строковые, числовые, рисунки и т. д.
Имя класса является именем нового типа данных (аналогично обычным типам данных: если есть тип int, то переменных типа int может быть любое количество). Например, описание студента с точки зрения деканата содержит разнообразную информацию: Фамилию, имя, отчество, курс, группу, успеваемость по разным предметам и т. д. Это описание не связано с конкретными студентами. При инициализации объекта класса (для конкретного студента) обеспечивается присвоение всем элементам класса фактических значений, и теперь объект класса будет связан с конкретным студентом.
Класс описывается с помощью ключевого слова class. Внутри класса могут объявляться как переменные (любых типов, включая вложенные классы), так и подпрограммы (методы) для обработки этих данных.
Доступ к данным и их изменение обеспечивается только с помощью подпрограмм, несущих ответственность за выполняемые операции, поэтому никакие другие подпрограммы не могут изменить защищенные данные случайно, по ошибке или преднамеренно. Этот принцип отсутствует в процедурно-ориентированном программировании, в котором значения переменных не связаны с их физическим смыслом. Например, одно и то же число может обозначать температуру воды, напряжение в электрической сети, или скорость материальной точки. В объектно-ориентированном программировании чтобы выполнить любую обработку информации, содержащейся в объекте класса, надо вызвать соответствующую подпрограмму, а к ней можно обратиться только через объявленный объект класса. Таким образом, за счет закрепления данных с подпрограммами для их обработки обеспечивается связь между смыслом числовых значений и их обработкой.
Помимо обычных в состав класса могут входить специальные подпрограммы, предназначенные для обработки событий, так называемые «обработчики событий». Эти подпрограммы обеспечивают интерфейс между пользователем и приложением, реагируя на события, связанные с элементами управления графического интерфейса: щелчки по кнопкам, выбор позиции меню и т. д.
Никакие операторы присваивания (кроме инициализации при объявлении переменных) вне подпрограмм не допускаются.
Извне обратиться (получить значение, изменить значение, вызвать подпрограмму) напрямую к любому члену класса невозможно. Для получения доступа к элементам класса объявляют объект этого класса. Например, один и тот же класс может описывать студента разных вузов. Для описания всех студентов вуза потребуется массив объектов. Объявление массива объектов класса и их инициализация связывают класс с конкретным вузом и конкретными студентами.
Внутри одного класса все объявленные в нем переменные доступны для всех остальных подпрограмм этого класса. Они являются как бы глобальными внутри класса.
Если во внешней по отношению к классу подпрограмме записать имя объекта и после него поставить точку, то из всплывающего списка можно выбрать необходимый элемент. Если элемента в списке нет, значит, либо он не доступен, либо не существует. Когда говорят о доступе, то имеется в виду именно такой способ обращения к элементам класса.
В языке C# к переменным с конкретными значениями обычно обращаются (через точку после имени объекта) не напрямую, а через специальную парадигму, называемую «свойством». Это позволяет более тонко управлять доступом. Например, можно разрешить считывание значения некоторой переменной и запретить ее изменение.
Если некоторая переменная описана с запретом для прямого обращения к ней извне, то можно оформить «свойство», которое будет иметь доступность для внешних подпрограмм, но при этом можно уточнить разграничение доступа, например, доступность только для чтения.
Такой подход исключает искажение смысла используемых переменных. Разграничение доступа называется инкапсуляцией.
Для описания свойств класса и разграничения доступа существуют перечисленные ниже атрибуты:
private Доступ к элементам возможен только из данного класса. Этот уровень доступа устанавливается по умолчанию, если не указан никакой другой уровень доступа.
public Открытый доступ к членам класса через объявленный объект этого класса или через «свойство».
internal Доступ к элементам только из данной сборки.
static Применительно к классам предполагается, что такой класс уже существует и его не надо объявлять (статические члены существуют на уровне класса, а не уровне объекта класса, пример вывод через класс Console). Другие применения атрибута static см. в описаниях членов класса.
sealed Запрещение наследования от данного класса.
abstract Указывается на возможность перегрузки методов.
partial Элементы класса могут размещаться в нескольких файлах.
Для создания объекта класса требуется:
• Объявить переменную этого класса, то есть выделить память для объекта класса.
• Инициализировать переменные, входящие в состав класса.
В одном классе можно объявить несколько переменных и подпрограмм. Подпрограммы, входящие в состав класса называют также «методами».
Переменным, являющимися членами класса, память выделяется при инициализации объекта класса, а объявленный объект класса становится физическим объектом и перестает быть обезличенным. Это аналогично понятию автомобиля. Марка автомобиля может быть одна (аналогия класса). Конкретные автомобили же разные (объекты класса «автомобиль»), имеющие индивидуальный номерной знак, цвет, владельца и т. д.
Форма объявления (описания класса) имеет вид:
«атрибуты» class «имя» // Заголовок описания класса
{
// Объявления и реализация членов класса
}
Наиболее распространенными атрибутами при описании класса являются доступ и возможность размещения класса в нескольких файлах (partial) , содержащего класс. Доступ может быть либо открытый (public), либо закрытый (private). (Закрытые классы чаще всего являются вложенными).
Пример заголовка описания класса:
public partial class Form1
В этом заголовке – Form1 имя класса, доступ открытый, файл может размещаться в нескольких файлах.
Форма объявления объекта класса (см. пример ниже) имеет вид:
Product tov = new Product();
Здесь Product - имя класса, tov – переменная, ссылающаяся на объект, но не сам объект. Операция new создает физическую копию объекта.
Доступ к членам класса с уровнем доступа public возможен только с помощью объявленного объекта класса. Форма обращения к элементам класса имеет вид (после объявленного объекта класса записана точка):
<объект класса>.<имя члена класса, уровень доступа public>
К закрытым членам класса доступ разрешен только методам, входящим в состав класса.
Рассмотрим пример оформления программы, которая обеспечивает реализацию заказа товаров. В примере рассматривается объявление двух классов (метод Main объявлен внутри класса Order)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Project2
{
// Класс Product – это типизированный набор данных
class Product // Товар
{
public int Prod_Num; // Штрих код товара
public string Prod_Name; // Название товара
public double Price; // Цена
}
class Order // Заказ
{
static void Main(string[ ] args)
{
// Объявление объекта tov типа Product
Product tov = new Product();
double Order_Cost; // Стоимость заказа
string Client_Name = "Ладошкин"; // Фамилия клиента
int Product_Quan = 7; // Заказанное количество
tov.Prod_Name = "молоток"; //
tov.Prod_Num = 123456;
tov.Price = 120.75;
Order_Cost = tov.Price * Product_Quan;
Console.WriteLine("Клиент " + Client_Name + " заказал товар
"
+ tov.Prod_Name + " в количестве "
+ Product_Quan + "
на сумму " + Order_Cost);
Console.ReadKey(); // Останов экрана пользователя
}
}
}
В рассмотренном примере инициализация объекта выполнена вручную (операторы вида pr.Price = 120.75;). Хотя такой метод и допустим, однако им пользоваться не рекомендуется, поскольку программист может забыть присвоить начальные значения переменным класса а, в некоторых случаях, выделить для них память. Кроме того, если выполнение прямого присваивания данных совмещено с объявлением класса, это привязывает класс к конкретному объекту и лишает класс универсальности.
При разработке приложений возникает потребность в списках объектов. Элементы объекта могут иметь различающиеся типы. Такие классы задают «типизированные» наборы данных, которые содержат только описание данных и ипредназначены для создания списков.
Для инициализации объектов применяется особая подпрограмма, называемая «конструктор», которая вызывается автоматически при создании объекта. У конструктора такое же имя, как и у класса, в котором он реализован, но он не имеет возвращаемого типа. Обычно конструктор имеет модификатор доступа public, чтобы его можно было вызывать через объект класса. Иногда требуется, чтобы обязательно была передана в класс некоторая информация, тогда конструктор без параметров объявляют с уровнем доступа private. Форма объявления конструктора в классе MyClass:
class MyClass // Объявление класса
{
// Объявления и методы для реализации класса
…
public MyClass() // Объявление конструктора без параметров
{
// Операторы реализации конструктора
}
}
Круглые скобки после имени конструктора указывают на то, что конструктор является подпрограммой. В скобках может быть ничего не записано (пустой список параметров), но может существовать список из нескольких параметров. Конструктор без параметров вызывается по умолчанию. В этом случае конструктор числовые данные обнуляет, ссылочным данным присваивает пустое значение, а булевским переменным устанавливает значение false.
Относительно классов без конструкторов с допуском через свойства. Конструктор с параметрами обязателен, когда новый объект формируется с помощью делегата (не присваивание, а передача аргументов), без конструктора выдается сообщение, что не реализован метод Add.
В приведенном выше примере класса для заказа товара переменным Prod_Num и Price класса Product будет присвоено нулевое значение, а переменной Prod_Name значение "" (пустая строка).
Конструктор с параметрами содержит в круглых скобках перечень аргументов, значения которых должны быть присвоены переменным класса. Каждый аргумент состоит из типа аргумента и его имени. Возвращаясь к примеру заказа товаров, конструктор с параметрами может быть оформлен как показано ниже в измененной программе.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Project2
{
class Product // Товар
{
private int Prod_Num; // Штрих код товара
private string Prod_Name; // Название товара
private double Price; // Цена
// Конструктор с параметрами
public Product (int Num, string Name, double Pr)
{
// Присвоение значений аргументов переменным класса
Prod_Num = Num;
Prod_Name = Name;
Price = Pr;
}
public int get_num()
{
return Prod_Num;
}
public string get_name() { return Prod_Name; }
public double get_price() { return Price; }
}
class Order // Заказ
{
private static double Order_Cost; // Стоимость заказа
private static string Client_Name; // Фамилия клиента
private static int Product_Quan;
static void Main(string[] args)
{
// Создание объекта Product с вызовом конструктора с параметрами
Product tov = new Product (123456, "Молоток", 120.75);
Console.WriteLine("
Введите имя клиента и количество товара
");
// Переменные Client_Name и Product_Quan из этого класса, они доступны
Client_Name = Console.ReadLine();
Product_Quan= int.Parse(Console.ReadLine());
Order_Cost = pr.get_price() * Product_Quan;
// Переменные Client_Name и Product_Quan из этого класса, они доступны
// Переменные Prod_Num, Prod_Name и Price
Console.WriteLine("
Клиент " + Client_Name + " заказал товар
" +
pr.get_name() + " (штрих код "+ pr.get_num()+") в количестве "+
Product_Quan + "
на сумму " + Order_Cost);
Console.ReadKey(); // Останов экрана пользователя
}
}
}
Ниже приведен результат выполнения программы
Переменные Order_Cost, Client_Name и Product_Quan объявлены в классе Order перед методом Main, поэтому теперь они доступны во всех методах (подпрограммах), которые могут быть добавлены в этот класс. Более того, перечисленные выше переменные имеют уровень доступа private, но поскольку обработка их выполняется в том же классе, они доступны для обычной обработки.
Ниже представлена схема присвоения значения закрытой переменной Price с помощью конструктора с параметрами. Конструктор имеет уровень доступа public, но, поскольку он входит в состав элементов класса, то ему доступны все элементы, имеющиеся в классе, поэтому он может присвоить значение своего параметра из списка аргументов закрытой переменной.
Ниже представлена схема вызова конструктора с параметрами. Конкретные значения параметров перечисляются в круглых скобках после имени класса.
Для обращения к членам класса Product в классе Order объявлен объект tov. Однако переменные в этом классе объявлены с атрибутом private, поэтому для обращения к ним оформлены функции get_num(), get_name() и get_price(). Структура этих функций одинакова, они содержат единственный оператор return, который возвращает соответствующее значение (например, return Prod_Num;). Привилегии доступа для них установлены public, поэтому в классе Order к ним можно обращаться через объект pr. Этот способ обращения к членам класса хотя и разрешен в языке C#, но его использовать не рекомендуется. Для обращения к членам класса рекомендуется применять «свойства».
Значения атрибутам товара в классе Product присваивается с помощью конструктора с параметрами. Для упрощения примера параметры в конструктор переданы в виде констант.
В связи с объявлением классов вводятся некоторые определения.
Термин Что обозначает
Тип-значение Когда одна переменная типа-значения присваивается другой переменной такого же типа, происходит копирование полей по членам. В случае простых переменных выполняется обычное присваивание.
Тип-ссылка Часто применяется термин «ссылочный тип». К этому типу относятся классы. Содержит ссылку на объект. В принципе это неявный указатель. При копировании ссылочных объектов в копии содержатся новые адреса всех компонентов исходного объекта.
Типизированный набор данных Класс, который содержит только информационное описание объекта (без методов для обработки данных). Применяется при работе с базами данных и при создании списков, обеспечивая проверку соответствия типов данных на уровне компиляции. В примере выше – Order обычный класс (выполняется обработка), а класс Product является типизированным набором данных (только описание и вспомогательные операции).
При создании объектов для них выделяется память. Если некоторый объект больше не используется, память, занятая им, должна освобождаться. В языке C# предусмотрена автоматическая «сборка мусора». Под этим понимается, что память, занятая объектом освобождается, если ссылки на объект отсутствуют. Пользователь может вручную выполнить освобождение памяти, вызвав «деструктор», который оформляется также, как и конструктор, но перед именем деструктора записывается тильда (‘~’). Однако, выполнять сборку мусора вручную не рекомендуется, поскольку среда времени выполнения осуществляет эту операцию во время минимальной загрузки центрального процессора (для повышения быстродействия). При закрытии приложения эта операция выполняется принудительно и автоматически, при этом обеспечивается отсутствие «утечки памяти».
Понятие класса в C#
Лекции по предмету «Программирование»