Читайте также:
|
|
Вопрос 1 Классы обзор элементов класса.
Классы и структуры — это, по сути, шаблоны, по которым можно создавать объекты. Каждый объект содержит данные и методы, манипулирующие этими данными. Класс определяет, то какие данные и какую функциональность может иметь каждый конкретный объект (называемый экземпляром) этого класса.
Структуры отличаются от классов тем, как они сохраняются в памяти и как к ним осуществляется доступ (классы — это ссылочные типы, размещаемые в куче, структуры — типы значений, размещаемые в стеке), и некоторыми свойствами (например, структуры не поддерживают наследование). Из соображений производительности легче использовать структуры для небольших типов данных. В отношении синтаксиса структуры очень похожи на классы. Главное отличие состоит в том, что в их объявлении используется ключевое слово struct вместо class.
При создании, как классов, так и структур используется ключевое слово new для объявления экземпляра. В результате объект создается и инициализируется.
Класс — это абстракция (реальная или концептуальная) объекта, принадлежащего какой-либо предметной области. Один шаблон класса можно использовать для создания нескольких объектов (экземпляров класса), которые обладают свойствами, определенными в классе.
class <Идентификатор_класса>
{
<Переменные_экземпляра>
<Методы>
}
Элементы класса являются языковыми конструкциями, составляющими тело класса. К примеру, переменные и методы экземпляра представляют собой два фундаментальных элемента класса. Однако классы настолько разнообразны, что С# содержит и несколько других элементов, придающих классу гибкость и расширяющих его возможности по взаимодействию с другими классами программы.
Обзор элементов класса.
В синтаксическом блоке представлен синтаксис, определения класса и описаны элементы, которые можно включать в определение класса.
Определение_класса::= <Данные члены> <Вложенные_типы>
class <Идентификатор_класса>:=<Переменные-члены>:= <Вложенные_классы>
{:=<Константы>:= <Вложенные_структуры>
<Члены_класса>:= <События>:= <Вложенные_перечисления>
Где <Функции-члены>
<Члены__класса>:= <Методы>
:= <Данные-члены>:= <Конструкторы>
:= <Функции-члены>:= <Деструкторы>
:= <Вложенные_типы>:= <Свойства>
:= <Индексаторы>
:= <Операции>
В первых строках отображен уже знакомый синтаксис: ключевое слово class, ими (идентификатор) класса и фигурные скобки, формирующие тело класса. Элементы класса можно разделить на три широкие категории:
· данные-члены,
· функции-члены;
· вложенные типы.
Данные-члены состоят из переменных-членов, констант и событий.
Переменные-члены (называемые также полями) используются для представления данных. Такая переменная может принадлежать или конкретному экземпляру (объекту) класса — в этом случае она называется переменной экземпляра, или самому классу — тогда она называется статической (объявленной static) переменной (или переменной класса). Напомним, что статический метод принадлежит классу, а не объекту (и вызывается для класса). То же самое справедливо и для статической переменной.
Переменная-член может быть объявлена только для чтения (с ключевым словом readonly). Такие переменные тесно связаны с константами-членами, но существует важное различие — значения последних устанавливаются в программе в процессе компиляции и существуют на протяжении ее исполнения. А значения readonly переменных-членов присваиваются им при создании объекта, и поэтому существуют, пока существует объект.
События объявляются подобно переменным-членам, но используются по-другому. При щелчке на кнопке (к примеру, ОК) в графическом пользовательском интерфейсе (GUI) соответствующий объект в программе генерирует (или возбуждает) событие (скажем, OKButtonClick), по которому определенная часть программы реагирует на действие пользователя. О приложении такого типа говорят, что оно управляется событиями, поскольку его следующее действие зависит от генерируемого события. Здесь уже неприменимо понятие программы, исполняющейся в той последовательности, в которой написаны ее операторы.
Функции-члены могут быть методами, конструкторами, деструкторами, свойствами индексаторами и операциями:
Метод — уже знакомая конструкция, которая, тем не менее, обладает многими еще неизученными свойствами.
Конструктор экземпляра, класса представляет собой метод, запускающийся по ключевому слову new. Он используется для инициализации переменных и других операциях при создании объекта.
Деструктор (называемый также завершающим методом) — известно объекты создаются и размещаются в определенной области памяти, где хранятся значения их переменных экземпляра и другие данные. Когда объект становится ненужным программе, занимаемую им память следует освободить для других объектов (иначе программа быстро начнет испытывать дефицит памяти). Деструктор, подобно своему собрату-конструктору, может содержать набор операторов, которые вызываются средой исполнения..
Свойства. Доступ к свойствамосуществляется так же, как к переменным-членам. Различие состоит в том, что свойство содержит операторы, которые исполняются подобно операторам метода, когда происходит обращение к нему. Они часто используются вместо аксессоров и мутаторов для доступа к закрытым переменным, поддерживая, таким образом, принцип инкапсуляции.
Индексаторы используются с классами, представляющими массивы. Так же, как свойства обеспечивают удобный доступ к отдельным переменным членам, индексаторы выполняют эту функцию для массивов, размещенных внутри классов.
Операции. Иногда имеет смысл (для повышения читаемости кода) объединить два объекта с помощью операции. Например, можно написать оператор наподобие totalTime = myTime + yourTime;, где все три переменных — объекты класса Timelnterval. Для достижения такой функциональности в классы включают операции-члены, которые задают набор команд, исполняющийся при объединении объектов в выражении с данной операцией. Этот процесс называют перегрузкой операции.
Вложенные типы — это классы, структуры, перечисления и интерфейсы, определенные в пределах тела класса. Они позволяют скрыть типы, которые используются только пределах класса. Подобно тому, как вспомогательные методы объявляются закрытыми для уменьшения внешней сложности класса, вложенные типы помогают снизить количество классов, необходимых для сборки программы.
Вопрос 2 Методы. Синтаксический блок.
Ссылочные параметры ref и out
Типы С# можно разделить на типы-значения и ссылочные типы. Когда методу передается значение ссылочного типа, все изменения в пределах метода отражаются и на исходной переменной. Если же аргументом метода является переменная типа-значения, она копируется в формальный параметр. В результате исходная переменная и переменная в методе являются разными, никак не связанными величинами. До сих пор подобные свойства редко использовались, поскольку любое вычисленное методом значение возвращалось в точку вызова. Но как быть, если требуется возвращать несколько значений? Здесь уже нельзя воспользоваться возвращаемым значением (поскольку так можно возвратить только одну переменную). Дня решения этой проблемы предназначены ссылочные параметры, которые объявляются с ключевым словом ref
public static void Swap(ref int a, ref int b)
Данный заголовок метода указывает, что а и b являются ссылочными параметрами. Вызов метода также должен содержать ключевое слово ref, например:
Swap(ref Value_1, ref Value_2)
Несоблюдение этого правила вызывает сообщение об ошибке на этапе компиляции.
OUT
Любой аргумент, передаваемый как ссылочный параметр, должен поддерживать присваивание значения (т.е. он не может быть, к примеру, Константой). Swap(ref 10, ref 20) так как числу 10 или 20 нельзя присвоить значение.
Следует отметить, что официальная терминология С# делает различие между функциями и методами. Согласно этой терминологии, понятие "функция-член" включает не только методы, но также другие члены, не являющиеся данными, класса или структуры. Сюда входят индексаторы, операции, конструкторы, деструкторы, а также — возможно, несколько неожиданно — свойства. Они контрастируют с данными-членами: полями, константами и событиями.
Объявление методов
В С# определение метода состоит из любых модификаторов (таких как спецификация доступности), типа возвращаемого значения, за которым следует имя метода, затем списка аргументов в круглых скобках и далее — тела метода в фигурных скобках:
[модификаторы] тип_возврата ИмяМетода([параметры])
{// Тело метода}Каждый параметр состоит из имени типа параметра и имени, по которому к нему можно обратиться в теле метода. Вдобавок, если метод возвращает значение, то для указания точки выхода должен использоваться оператор возврата вместе с возвращаемым значением.
Если метод не возвращает ничего, то в качестве типа возврата указывается void, поскольку вообще опустить тип возврата невозможно. Если же он не принимает аргументов, то все равно после имени метода должны присутствовать пустые круглые скобки. При этом включать в тело метода оператор возврата не обязательно — метод возвращает управление автоматически по достижении закрывающей фигурной скобки.
Возврат из метода и возврат значения
В целом, возврат из метода может произойти при двух условиях. Во-первых, когда встречается фигурная скобка, закрывающая тело метода. И во-вторых, когда выполняется оператор return. Имеются две формы оператора return: одна — для методов типа void (возврат из метода), т.е. тех методов, которые не возвращают значения, а другая — для методов, возвращающих конкретные значения (возврат значения).
Вопрос 3 Перегрузка методов.
Перегрузка методов. Вызов методов с одинаковым именем и разными аргументами
Для того чтобы лучше понять, что такое перегрузка методов необходимо рассмотреть пример вычисления расстояния между двумя точками на плоскости. Предположим, что на плоскости расположены две точки с координатами: и . Воспользовавшись простейшим правилом геометрии расстояние между этими точками будет равно: Ниже представлен код программы.
Предположим, что нам необходимо написать программу вычисляющую значение длинны отрезка с параметрами типа int. Код будет выглядеть следующим образом:
class Plane
{
…
public double DistanceInt(int x1, int yl, int x2, int y2)
{
return Math.Sqrt(Math.Pow(x1-x2,2) + Math.Pow(y1-y2. 2));
}
…
}
Список формальных параметров метода DistanceInt содержит четыре значения типа int( или неявно преобразуемого в него ). Однако если потребуется найти расстояние для четырех аргументов типа double, будет необходимо создать другой метод класса Plane, DistanceDouble, который выглядит следующим образом:
class Plane
{
…
public double DistanceDouble(double x1, double yl, double x2, double y2)
{
return
Math.Sqrt(Math.Pow(x1-x2,2) + Math.Pow(y1-y2. 2));
}
…
}
Возможен еще и другой случай, когда для представления точек на плоскости используется некий класс Point. Каждый объект этого класса содержит две закрытые переменные экземпляра . Для доступа к ним применяются соответствующие методы (асессор и мутатор).
class Point
{
private int x = 0;
private int y = 0;
public void setX(int newX)
{
x = newX;
}
public void setY(int newY)
{
y=newY;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
}
Теперь для расчета расстояния (с помощью методов созданных ранее) удобнее указать четыре числовых аргумента и два объекта:
public double DistanceObjects(location L1, location L2)
return
Math.Sqrt(Math.Pow(L1.getX()-L2.getX(),2)+Math.Pow(L1.getY() - L2.getY(),2));
}
Из написанных кодов можно сделать следующий вывод, что три метода с разными именами, по существу, решают одну задачу — вычисляют расстояние. Разумеется, было бы проще и естественнее (независимо от типа аргументов — int, double или Location) использовать одно имя Distance.
При этом компилятор автоматически выбирает правильный путь для обработки аргументов. Такой подход возможен благодаря перегрузке метода.
Эта концепция позволяет определять в одном классе несколько различных методов с одним именем, но разными наборами формальных параметров и реализацией. Для перегрузки метода в данном случае (чтобы три приведенных вызова были корректными вместе с возвращаемыми ими значениями) достаточно просто присвоить всем трем методам одно имя — Distance. Тело каждого из них останется без изменений, а заголовки будут выглядеть так:
public double Distance(int x1, int y1, int х2, int y2)
public double Distance{double x1, double yl. double x2, double y2)
public double Distance(Location LI, Location L2)
Теперь, когда компилятор встречает оператор Plane.Distance(10, 10, 20, 30), он совершает следующие действия. Вначале в классе Plane производится поиск метода с именем Distance. Компилятор находит три таких метода. Он выбирает тот из них, чей набор формальных параметров совпадает с аргументами в вызове. Такое совпадение требует, чтобы:
1 Число аргументов в вызове было равно числу формальных параметров.
2 Каждый аргумент имеет тип, совместимый с типом соответствующего ему формального параметра.
Следуя этой процедуре, компилятор выбирает метод Distance с заголовком:
public double Distance(int x1, int у1, int х2, int y2) С перегрузкой метода связана важная концепция — сигнатура метода. Имя метода вместе с числовым типом и порядком формальных параметров составляют сигнатуру метода.
Однако стоит отметить следующие исключения.
Возвращаемое значение не включено в сигнатуру метода. Таким образом, следующие три заголовка имеют одинаковую сигнатуру (несмотря на то, что первый возвращает значение double, второй int, а третий не возвращает значения):
public double Sum (double a, double b)
public int Sum (double a, double b)
public void Sum (double a, double b)
Ключевое слово params всигнатуре метода игнорируется. Следовательно, следующие два заголовка имеют одинаковую сигнатуру:
public double Sum (params double[] numbers)
public double Sum (double[] numbers)
Имена формальных параметров не включаются в сигнатуру метода. Сигнатуры двух следующих методов совпадают:
public int Sum (double x, double y)
public int Sum (double a, double b)
Все методы в классе должны иметь разные сигнатуры. Поскольку имя метода — один из нескольких атрибутов, определяющих сигнатуру метода, в одном классе можно определить несколько методов с одним именем при условии, что остальные элементы сигнатур различаются. Такие методы называются перегруженными,
Перегруженные методы широко используются в классах.NET.
Рассмотрим, как согласуется перегрузка методов и неявное преобразование.
Дата добавления: 2015-10-23; просмотров: 88 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Розділ 2. Свобода, як основний мотив Пушкіна | | | Вопрос 13 Полиморфизм как концепция ООП. |