Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Объектно-ориентированное программирование. Учебник для СПО

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать

ет свойство новым значением с использованием этого ключевого сло­ва. Обычно свойства используются для доступа к закрытому полю класса. При наличии одного лишь метода 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-
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]