Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Объектно-ориентированное программирование. Учебник для СПО
.pdf
ет свойство новым значением с использованием этого ключевого слова. Обычно свойства используются для доступа к закрытому полю класса.
При наличии одного лишь метода get поле доступно только для чтения,
а при наличии одного метода set — только для записи.
Примеры:
get
{ return x }; // Получение значения
set
{ x = value}; // Запись значения
Свойство можно назвать «оберткой» для переменной объекта. Свойства, как и поля, могут участвовать в выражениях.
Свойства позволяют избежать рассогласования связанных данных
в полях при изменении части этих данных (например, даты рождения
и возраста, места жительства и места работы, комплектующих деталей
и завода-поставщика и т.д.). Изменение в одном из полей для связанных данных обязательно должно вести к изменению других полей. Рассмотрим пример согласованного получения и установки значений полей,
учитывающих предписанные требования.
using System;
class ABC
{
private int x, y=10, z; // Переменные
public int X; // Объявление свойства X
set / /Установка значений переменных
{
x = value; // Аргумент по умолчанию value
z = y -value;
}
get // Получение значения z переменной
{
return x;
}
}
public ABC(int x) // Конструктор
{
this.x = x;
this.z = y -x;
}
-161-

}
class Applic(x)
{
static void Main(string [] args)
{
ABC abc = new ABC(22); // Создание экземпляра
abc abc.X = 30; // объект.Свойство
Console.WriteLine(abc.X)
}
}
Здесь создано поле ABC.x и свойство ABC.X.
Свойства являются методами, но клиентами они воспринимаются как поля. При доступе к полю и к свойству (с помощью set и get) отличий нет. Свойства позволяют использовать инструкцию вида объект.
поле
. Свойства похожи на поля, так как их можно и изменять, и использовать в выражениях.
Текущее возвращаемое значение свойства может храниться в поле
или вычисляться динамически во время работы программы. Таким образом, чтение и установка свойства приводят к вызову соответствующих
процедур доступа.
Рассмотрим следующий фрагмент программы:
MyC x = new MyC (8);
MyC y = new MyC (14);
x.A = 5; // объект.Свойство
y.A = 2; // объект.Свойство
Здесь созданы два объекта класса MyC, содержащего свойства A,
и производится ссылка на свойства объекта (так же, как и на поле объекта), но при присвоении свойству значения программа изменяет свойство объекта в процедуре доступа. Поэтому в процедуре возможны
различные операции, например: проверка присваиваемого значения
на допустимость, информирование о вносимых изменениях, передача
по Интернету и др.
Свойства наследуются. Допускается создание статических, виртуальных и абстрактных свойств. Со свойствами могут использоваться модификаторы virtual, override или abstract.
Если свойство объявлено как abstract, то оно не имеет реализации в базовом классе, и в этом случае методы set и get не содержат бло-
-162-

ков в базовом классе. Объект абстрактного класса можно только объявить,
но не создать. Пример объявления абстрактного свойства:
public abstract int X
{
set;
get;
}
Все производные классы должны реализовать у себя это свойство,
т.е. перегрузить его, используя ключевое слово override при объявлении
свойства в производных классах.
Если свойство объявлено как virtual, то производные классы могут
определить свой вариант реализации свойства или же использовать реализацию в базовом классе.
Пример объявления виртуального свойства:
public virtual int z
{
set
{
y = value;
}
get
{
return y;
}
}
Процедуры доступа виртуального свойства должны быть определены в дочернем классе.
Для ссылки на статические свойства используется имя класса, а не
объект класса. При объявлении статического свойства недопустимо использование ключевых слов virtual, abstract и override.
Вместо поля только для чтения readonly можно использовать свойство с доступом только get.
Подобными возможностями можно наделять не только поля, но
и массивы. Для этого используются индексаторы с методами доступа get
для извлечения данных из массива и (или) set для записи данных в такой
массив. В объявлении индексатора принимает участие параметр, заклю-
-163-

ченный в квадратные скобки и играющий роль индекса. Параметр индексатора применяется для организации доступа к элементу массива.
Свойства могут быть перегружены в производных классах.
Вопросыизадания
?
1. Что называется свойством в программах на C#?
2. В чем состоят достоинства использования свойств по сравнению
с операциями присваивания?
3. Какие типы методов-свойств используются и для каких целей?
4. Как объявлять свойства?
5. Что означают ключевые слова
get и set?
6. Для каких целей используется ключевое слово value?
7. Какое свойство называется абстрактным?
8. Какое свойство называется виртуальным?
Упражнение
В приведенной программе введены две взаимосвязанных характеристики — период (period) и частота (frequency), описывающие некоторую динамическую систему.
using System
{
class Oscillation
{
private double period; //Поле (период)
private double frequency; //Поле (частота)
public double Frequency //Объявление свойства
{
set //метод для установки свойства
{
frequency = value; //имя по умолчанию value
period = 1/ value;
}
get //метод – аксессор для получения свойства
{
return frequency;
}
}
-164-

public double Period; //Объявление свойства
{
set
{
period = value; //имя по умолчанию
frequency = 1/ value;
}
get
{
return period;
}
}
public Oscillation (double frequency) //Объявление
конструктора
{
this.frequency = frequency;
this.period = 1/ frequency;
}
}
class OscillationApplication
{
static void Main(string [] args)
{
Oscillation x = new Oscillation (10);
x.Frequency =15;
Console.WriteLine(x.Period, x.Frequency);
}
}
}
Указать, как методы get и set управляют доступом к полям fre-
quency
и period. Указать, как изменение значения одной из характери-
стик приводит к изменению другой характеристики.
5.8.ПЕРЕГРУЗКАМЕТОДОВ
Перегрузка методов и операций — это одно из проявлений принципа полиморфизма, заложенного в основу языков ООП и, в частности, языка C#.
Операции могут вести себя по-разному. В зависимости от контекста одинаковые символы используются для выполнения различных дей-
-165-

ствий. Например, операция + может отражать не только арифметическую
операцию сложения, но и конкатенацию строк, и объединение делегатов.
Поведение операторов для пользовательских классов и структур можно
изменять, т.е. перегружать операции.
Другими примерами перегруженных операций являются операции
с векторами, комплексными числами, простыми дробями, матрицами.
Они выполняются по другим правилам, чем арифметические операции,
и должны быть описаны программистом в теле метода, определяющего
работу этих операций.
Имя какого-либо метода может не быть уникальным. Объявление и существование в классе нескольких общих (или близких) по назначению методов с одним и тем же именем называется перегрузкой, а одноименные
методы называются перегруженными. Среди методов с одинаковым именем компилятор распознает требуемый перегруженный метод по его аргументам (количеству и/или типу). Отличие лишь в типе возвращаемого значения недостаточно для идентификации перегруженного метода.
Перегруженные методы легче найти в библиотеке и удобнее использовать, когда требуется решать схожие, подобные задачи, так как перегруженные методы — это множество методов с одним именем. Например,
площадь треугольника можно вычислить по высоте и основанию, по трем
сторонам, по двум сторонам и углу между ними и т.д. В этом случае метод
вычисления площади треугольника удобно называть одним именем и передавать ему один из выбранных наборов аргументов (фактически выбирать метод расчета из множества).
Уникальной характеристикой перегруженных методов является их
сигнатура (имя метода и список формальных аргументов). Так как имя для
перегруженных методов одинаково, то должны отличаться формальные
аргументы (число аргументов, типы аргументов и/или служебные слова).
Перегрузка делает более понятными исходные тексты программ, так
как используются привычные обозначения операторов. Она широко используется при построении библиотеки FCL. Перегружая какой-либо метод из имеющихся в библиотеке классов, можно наделить его новыми
функциями. Перегрузка особенно полезна при большом числе перегружаемых методов. Однако вместо перегруженных методов иногда обосновано использование методов с разными именами и своими аргументами.
Еще одно достоинство перегрузки состоит в их использовании для
построения экземпляров класса различными конструкторами. В отдельном классе имена конструкторов должны быть одинаковыми и совпадать
с именем класса, но отличаться конструкторы будут передаваемыми аргументами.
-166-

�
(a + b + c) ∙ (–a + b + c) ∙ (a – b + c) ∙ (a + b – c) / 8
a
2
∙sin
(
beta
)
∙ sin(gamma)
2
alpha
1
2
При объявлении перегруженной операции должны присутствовать
модификаторы static или public. Напомним, что статичные методы, объ-
единенные классом, используются, если они логически связаны и не имеют
отношения к объектам программы.
В качестве примера создадим класс статичных методов без перегрузки, позволяющих вычислять площадь треугольника тремя разными
способами, и имеющих разные имена. Пусть a, b, c – стороны треугольника, alpha, beta, gamma — углы, лежащие напротив этих сторон соответственно, а p = (a + b + c) / 2 — полупериметр. Класс создаваемых здесь методов позволяет вычислять площадь треугольника 3 способами:
�
1. По трем сторонам треугольника S =
=
p ∙ (p – a) ∙ (p – b) ∙ (p – c)
(формула Герона).
=
2. По одной стороне и двум углам S =
∙ sin(
gamma = 180 – alpha – beta.
3. По двум сторонам и углу между ними S =
a ∙ b ∙ sin(gamma).
Следующая программа не использует перегруженных методов.
using System;
class SquareOfTriangular
{
public static float ST1(float a, b, c) //стороны
{
return sqrt( (a+b+c)*(-a+b+c)*(a-b+c)*(a+b-c)/8 );
}
public static float ST2(float a, alpha, beta) //Сторона a,
углы alpha, beta, gamma
{
return a*a*sin(beta)*sin(180 - alpha - beta) / 2 / sin(alpha);
}
public static float ST3(float a, b, gamma) //Стороны a, b,
угол gamma
{
return a*b/2*sin(gamma);
}
class StaticMethods
{
static void Main (string[] arg)
{
)
, где
-167-

float x = 7,2, y = 6,5, z = 8,1;
Console.WriteLine("Площадь треугольника со сторонами
{0} {1} {2} равна {3}", x, y, z, SquareOfTriangular. ST1(x, y, z) );
Console.ReadLine();
}
}
В классе SquareOfTriangular нет ни одного поля. Метод Static-
Methods
выводит на консоль три стороны и площадь треугольника, вы-
численную по запрошенному методу ST1. Математические методы в этой
программе имеют модификатор public и доступны из любого места программы. Для ссылки на них указывается класс и через точку имя метода, например SquareOfTriangular.ST1(x, y, z). Все три метода имеют
одинаковый список и тип параметров, поэтому в рассмотренной программе должны именоваться индивидуально.
Теперь рассмотрим программу с перегруженными методами вычисления площади треугольника. Все методы будут иметь одно имя ST, но от-
личаться типом аргументов. Пусть стороны имеют тип double, а углы —
тип float.
Программа будет иметь следующий вид:
using System;
class SquareOfTriangular
{ // Параметры: стороны
public static float ST (double a, b, c) {
// Параметры: сторона a, углы alpha и beta
public static float ST (double a, float alpha, float beta)
{
… }
// Параметры: стороны a, b, угол gamma
public static float ST (double a, double b, float gamma)
{
… }
class StaticMethods
{
static void Main (string[] arg)
{
double x = 7,2, y = 6,5, z = 8,1;
Console.WriteLine("Площадь треугольника со сторонами {0} {1} {2} равна {3}", x, y, z, SquareOfTriangular.
ST(x, y, z) ); Console.ReadLine();
}
}
… }
-168-

Класс может иметь не только перегруженные методы, но и перегруженные конструкторы. Например, один конструктор может не иметь
параметры, а другой конструктор с тем же именем их иметь. Это иллюстрируется следующим кодом:
class MyClass
{
int x;
byte y;
public MyClass() //Конструктор без параметров
{
xx=-8; yy= 5;
}
public MyClass(int x, byte y) //Конструктор с 2 параметрами
{
xx=x; yy=y;
}
}
Создадим два объекта:
MyClass obj1, obj2;
obj1= new MyClass();
obj2= new MyClass(5, 0);
Первый объект obj1 создан с помощью конструктора без параметров
(с заданными значениями xx = -8 и yy = 5), а второй объект obj2 создан
с помощью конструктора с параметрами xx = 5 и yy = 0.
Ниже приведен пример перегрузки в дочерних классах.
using System;
class A //Базовый класс
virtual public void MakeIt()
{
Console.WriteLine("Базовый класс А");
}
class B : A// Дочерний класс
{
override public void MakeIt()
{
Console.WriteLine ("Дочерний класс B");
-169-

}
}
class C : A //Дочерний класс
{
override public void MakeIt ()
{
Console.WriteLine ("Дочерний класс С");
}
}
В базовом классе A содержится виртуальная функция MakeIt, выводящая на консоль некоторое сообщение. В дочерних классах B и C эта
функция перегружается для вывода собственного сообщения.
Синтаксис метода перегрузки имеет вид:
public static Тип operator ЗнакОперации(Параметры)
{
…//Тело метода}
Существуют и некоторые ограничения на создание перегруженных операторов. Операцию присваивания нельзя перегружать, приоритеты существующих в языке операторов должны сохраняться, параметры в выполняющий перегрузку метод должны передаваться только
по значению.
Вопросыизадания
?
1. Что называется перегрузкой метода и перегрузкой операции?
2. Для каких целей используются перегруженные методы? В чем со-
стоит их достоинство?
3. Должно ли имя метода в классе быть уникальным?
4. Что называется сигнатурой метода? В чем отличие сигнатур для
перегруженных методов?
5. Привести примеры перегруженных методов для генерации псев-
дослучайных чисел из библиотеки классов.
6. Дать характеристику перегруженных конструкторов (класс, объек-
ты, число и тип аргументов):
SomeClass x = new SomeClass(); SomeClass y = new SomeClass(25,
true);
-170-
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
