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

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

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать

Таким образом, в отличие от других языков ООП (например, языка C++) множественное наследование в C# не поддерживается. В C# также не допускается рекурсивное или циклическое наследование классов (ког­да, например, два класса наследуют друг от друга). Множественное насле­дование в C# при необходимости решается с помощью специальных клас- сов, называемых интерфейсами.
В базовом (родительском) классе отражается все общее, что есть в до­черних классах, т.е. все, что обобщает поведение дочерних классов. Спе­цифические особенности поведения дочерних классов в базовом классе не указываются.
При наследовании возможно переопределение или добавление но­вых данных и (или) методов в дочерних классах. Переопределив метод родителя, потомки могут вызывать собственный метод или метод ро­дителя. Класс-потомок может также учитывать любые события, предус­мотренные в нем. Однако потомок не может наследовать конструкторы из родительского класса.
Отношение наследования означает способность классов порождать классы-наследники с одинаковыми сущностями (методами, полями, свойствами, делегатами), а также с новыми возможностями, отличающи­ми их от родительских классов. Наследование позволяет уточнить, как должны выполняться операции класса. В потомках можно добавить но­вые свойства — поля класса, но нельзя отменить или изменить модифика­торы или типы полей, наследованные от родителя. Потомкам все извест­но о своих предках, но не наоборот.
Таким образом, принцип наследования в ООП позволяет выстраи­вать иерархию классов. Иерархия классов фактически моделирует опи­сываемую предметную область. Вместе с тем наследование в некотором смысле нарушает принцип инкапсуляции, так как производному классу доступны детали реализации родительского класса.
Надежность программы напрямую связана с ее простотой. Чем мень­ше добавляется программного кода в существующий код, тем меньше возможность ошибок. Очевидное достоинство использования отношений наследования состоит в том, что классы-потомки не повторяют наследу­емый код своих родителей, поэтому объем программного кода умень­шается. Если нужно создать новый класс, незначительно отличающийся от имеющегося класса, то не следует объявлять уже существующие поля и методы. Достаточно в новом классе определить только новые поля, ме­тоды и свойства. Создавая класс-наследник, можно пользоваться всеми многочисленными возможностями класса-родителя (наследовать их). Особенности класса-потомка могут быть учтены не только путем объяв-
-81-

ления новых способностей, но и запрета на некоторые свойства, методы или события класса-родителя. Это позволяет учесть различия между клас­сами-потомками и классами-предками.
Экземпляр класса-наследника обязательно является также экзем­пляром родительского класса. Таким образом, класс потомка представ­ляет собой специализированный частный случай родительского класса.
Отношение наследования отражает конкретизацию понятий.
Достоинство наследования проявляется тогда, когда некоторый ба­зовый класс имеет общую функциональность для нескольких других клас­сов. В наибольшей степени эффект от наследования проявляется при ис­пользовании обширной библиотеки классов.
Наследование класса определяется статически на этапе компиляции, т.е. наследование фиксировано, его нельзя изменить в процессе работы программы.
Наследование классов в программном коде выражается следующей синтаксической конструкцией:
class ДочернийКласс : РодительскийКласс
Например, при объявлении класса экскаваторов указывается, что он является объектом (подмножеством) класса дорожных машин:
class Excavator: RoadMachine
Пусть объявлен класс Son — наследник класса Father:
public class Son: Father
{
}
Здесь тело класса Son пусто, но его объекты наследуют все поля и ме­тоды (кроме конструктора) класса Father и поэтому могут делать все, что могут делать объекты родительского класса. Никаких новых возможно­стей в класс Son здесь не было добавлено. Добавление, например, стро­ки в теле потомка protected int x; означает новое поле класса, закрытое для клиентов этого класса, но открытое для его потомков.
Потомок может создать собственный метод с именем, отличным от имен наследуемых методов. Например, в теле рассматриваемого клас­са-потомка может быть создан новый метод:
-82-

public void MyMethod()
{
Console.WriteLine("Метод класса Son");
}
Класс-потомок может изменять наследуемые им методы (в отличие от полей родительского класса, которые изменять нельзя).
Метод производного класса может вызывать одноименный метод базового класса, но тогда необходимо использовать ключевое слово base для того, чтобы компилятор мог их различать (избежать конфликта имен). Например, в производном классе используется метод MyMethod(), кото­рый, в свою очередь, обращается к одноименному методу базового клас­са в операторе:
return base.MyMethod()+2,3*s;
Ключевое слово return означает возврат результата (в данном слу­чае для производного класса).
Базовый класс может содержаться в стандартной библиотеке классов FCL. Пусть объявлен класс ManagButton с помощью оператора вида
class ManagButton : Form
Класс Form входит в пространства имен System.Windows.Forms и создан компанией Microsoft для работы с различными формами. Здесь указывается на возможность наследования классом ManagButton всех способностей базового класса Form (он должен быть объявлен как класс в указанном пространстве имен). Структура программы с родительским классом BaseClass и двумя классами-наследниками может иметь вид:
using System;
protected class BaseClass
{
}
class DaughterClass1 : BaseClass
{
}
class DaughterClass2 : BaseClass
{
}
-83-

class MyApplication
{
public static void Main() {
}
}
Наследовать можно все члены базового класса, которые определен­ны как public, protected или internal (но не члены с модификатором
private, а также не конструкторы).
Каждый из дочерних классов может, конечно, иметь свои собствен­ные члены (поля, методы и т.д.), которых нет в базовом классе. Иногда в дочернем классе необходимо не только что-нибудь добавить, но и пере­определить (изменить) некоторые члены базового класса.
Рассмотрим причины отсутствия множественного наследования клас­сов в программах на C#. Множественное наследование позволяет классу быть порожденным сразу от нескольких родительских классов и насле­довать поведение всех своих предков. Пусть, например, имеются клас­сы «Токарь» и «Электрик», включающие рабочих указанных профессий. Для того чтобы получить класс рабочих, обладающих профессиями тока­ря и электрика, необходим новый класс. Он может быть получен из ука­занных классов множественным наследованием. В случае множественно­го наследования структура связей между классами преобразуется в сеть. Ее можно представить множеством деревьев, которые могут содержать сросшиеся кроны.
Множественное наследование часто приводит к сложным пробле­мам проектирования и реализации. Две основные проблемы множест­венного наследования — это коллизия имен и наследование от общего предка (дублирующее наследование).
Коллизия имен — это ситуация, когда два или более интерфейса имеют методы с одинаковыми именами и сигнатурой. Для ее решения применяют склеивание методов, если разные интерфейсы задают один и тот же метод, или переименование методов.
Проблему наследования от общего предка можно пояснить простым примером. Пусть класс D является наследником классов B и C, а они явля­ются наследниками класса A. Тогда класс D наследует методы и свойства класса A дважды (от классов B и C, а они могли по-разному переопреде­лить методы родителя A).
Механизм интерфейсов, имеющийся в языке C#, решает проблему множественного наследования.
Рассмотрим пример создания родительского и дочернего классов. Необходимо создать родительский класс окружностей, имеющих в каче-
-84-

стве параметров координаты центра на плоскости и радиус. На его осно­ве необходимо создать дочерний класс, имеющий новое поле для типа ли­нии и метод для его установки.
class myCircle // Базовый класс
{ // поля класса (Объявление переменных):
int xPos; // Координата центра x int yPos; // Координата центра y int radius; // Радиус окружности public myCircle () // Конструктор класса
{
xPos = yPos = radius = 0;
} public void SetPosition(int x, int y) // Метод для позиции: {
xPos = x; yPos = y;
} public void SetSize(int R) // Метод для радиуса: {
radius = R;
}
}
В конструкторе создана окружность с центром в начале коорди­нат и с нулевым радиусом. Метод SetPosition устанавливает положе­ние окружности на плоскости с координатами x и y, а метод SetSize — ее размер.
После описание класса myCircle определим его работу:
myCircle A; // Объявление переменной для объекта A
A = new myCircle (); // Создание объекта A (окружности)
A.SetPosition (2, 5); // Установка позиции центра
A.SetSize(10); // Установка размеров окружности
Теперь следует создать дочерний класс окружностей CurveMyCircle, имеющий новые сущности — тип линии окружности. Тип линии (точеч­ная, пунктирная, сплошная и т.д.) будем указывать целым числом без зна­ка. Дочерний класс по сравнению с базовым классом должен иметь поля и методы для работы с типами линий.
-85-

class CurveMyCircle : myCircle //наследование от myCircle
{
byte typeOfCurve // Поле типа линии public void SetCurve(byte c)
{
typeOfCurve = c;
}
}
Имя дочернего класса CurveMyCircle отделено двоеточием от име­ни базового класса myCircle. Дочерний класс наследует все поля и мето­ды базового класса. Но в новом классе появляются одно новое поле для объявления типа линии typeOfCurve и один метод SetCurve для уста­новки значений поля для типа линии.
Для описания работы дочернего класса введем новый класс CurveMy-
CircleApplication
class CurveMyCircleApplication
{
static void Main (string[] args) {
CurveMyCircle U; // Объявление объекта U U=CurveMyCircle(); //Создание объекта U (окружности) U.SetPosition(5, 2); // Установка позиции центра U.SetSize(10); // Установка размеров окружности U. SetCurve(3); // Установка типа линии Console.ReadLine();
}
}
c методом Main:
При передаче управления методу Main он создает объект со ссылоч­ной переменной U. Он устанавливает для этого объекта определенные по­зиции центра и радиус с помощью методов U.SetPosition и U.SetSize базового класса myCircle. Обращение к методам базового класса из про­изводного класса можно выполнить потому, что методы базового класса имеют модификатор доступа public.
Кроме того, в методе Main устанавливается также тип линии для окружности с помощью метода SetCurve производного класса.
Теперь сведем все вместе. Структура программы имеет вид:
using System;
namespace Circle
{
-86-

class myCircle // Базовый класс
{ }
class CurveMyCircle : myCircle // Наследование
{ }
class CurveMyCircleApplication // Работа с классами
{
static void Main (string[] args)
} // Создание и установка параметров объекта
{
}
}
Слово new, размещенное в производном классе перед именем мето­да базового (родительского) класса, позволяет заменить реализацию ба­зового класса и таким образом учесть специфику производного класса. Так осуществляется подмена (override) методов.
Если некоторый класс не должен быть родительским для других классов (есть запрет на создание потомков), его нужно отметить ключе­вым словом sealed. Это слово запрещает наследование. Такой класс на­зывается изолированным. В следующем фрагменте программы компи­лятор обнаружит ошибку:
sealed class A // Запрет на наследование
{
}
class B : A // Неверно, так как наследование запрещено
{
}
 Вопросыизадания
?
1. Что называется классом-родителем, классом-предком, классом-
потомком, дочерним классом?
2. Какой тип отношений существует между базовыми и производны-
ми классами?
3. В чем заключаются преимущества наследования при проектиро-
вании и реализации программ?
4. Как указать в программе возможность наследования?
5. Как учесть характерные особенности производного класса?
6. Что означают простое и множественное наследования?
7. Какие проблемы возникают при множественном наследовании?
Приведите примеры.
-87-

8. Укажите родительский класс и класс-наследник:
class Choke: Component // Choke – это дроссель
class PotassiumCyanide: DangerousSubstance //Цианистый калий
class Silver: Metals // Серебро
9. Как объявить класс Diamond_Drill (Алмазный бур) наследником
класса Bore (Бур)?
10. Как запретить наследование от некоторого класса?
11. Для каких целей используется ключевое слово return?
12. Какие классы называются изолированными?
13. Изменяется ли отношение наследования в процессе выполнения
программы?
 Упражнения
1. Указать отношение иерархии для классов объемных геометриче­ских объектов: кругов, конусов, цилиндров. Выявить базовый и производ­ные классы и их взаимосвязи.
2. В программе вычисления налога на доходы физических лиц ис­пользуется базовый класс BaseTax с переменными salary (зарпла­та) и
tax (величина налога), а также метод вычисления налога по став-
ке 13 % для резидентов. В дочернем классе налогов для нерезидентов
ForeignerTax наследуются переменные зарплаты и величины налогов,
вводится новая переменная
country (страна) и используется метод исчи-
сления налога по новой ставке 35 %.
using System; class BaseTax //Базовый класс налогов
{
protected decimal salary = 0; //зарплата protected decimal tax = 0; //величина налога public void Calc (decimal salary, decimal tax) //расчет налога
{
tax = 0.13*salary return tax
}
} class ForeignerTax: Tax //Класс налогов для иностранцев {
-88-

public string country //страна public void Calc (decimal salary, decimal tax)
{
tax = 0.35*salary return tax
}
} class TaxApplication {
static void Main(string [] args) {
BaseTax baseTax = new BaseTax (); salary = 5555.55 Console.WriteLine("налог по ставке 13% = ", tax) ForeignerTax foreignerTax = new ForeignerTax () salary = 7777.77; country = "UK"; Console.WriteLine("налог = " + tax + ", страна " + country) Console.ReadLine()
}
}
Изучить программный код. Определить:
- родительский класс;
- класс-потомок;
- свойства родительского класса;
- характерные свойства класса-потомка;
- характеристики экземпляра потомственного класса;
- сообщения, выводимые на консоль.
3. Написать программный код, в котором описаны родительский и производный классы с указанием типа полей. Создать один экземпляр класса-потомка.
Родительский класс Tool (Инструмент) имеет характеристики:
- название name;
- масса инструмента mass;
- используется ли электричество needElectricity;
- инвентарный номер number.
Производный класс Spanner (Гаечный ключ) отличается от него осо-
быми свойствами:
- наибольший размер гайки size;
- тип ключа (накидной, торцевой) typeOfSpanner.
-89-

4. Написать программный код, в котором описан родительский класс с несколькими характеристиками и дочерний класс с 1–2 особыми свой­ствами. Создать один экземпляр производного класса.
Классы выбрать по номеру варианта N.
Родительский
N
1
класс
MechTool
(Механические инструменты)
MechTool
(Механические
2
инструменты)
MechTool
(Механические
3
инструменты)
Cartridge
4
(Патроны)
Bed (Пласты
5
горной породы)
Computer
6
(Компьютеры)
Memory
7
(Память)
Memory
8
(Память)
Lathe
(Токарные
9
станки)
Lathe
(Токарные
10
станки)
Alkali
11
(Щелочи)
Radio_Part
12
(Радиодетали)
Дочерний
класс
Screw_driver
(Отвертки)
Pliers
(Кусачки)
Hammer
(Молотки)
Sporting_ Cartridge
(Охотничий патрон)
Oil
(Нефтяной)
Drawing_ Board
(Планшетный)
RAM (Random
Access Memory, Оперативная память)
Disc
(Дисковая)
Turret
(Револьверный)
Chucking
(Патронный)
Potash
(Поташ, K2CO3)
Capasitor
(Конденсаторы)
Родительский
N
13
14
15
16
17
18
класс
Radio_Part
(Радиодетали)
Radio_Part
(Радиодетали)
Radio_Part
(Радиодетали)
Acid
(Кислоты)
Acid
(Кислоты)
Building_Mat
(Строительные материалы)
Acid
19
(Кислоты)
Acid
20
(Кислоты)
Acid
21
(Кислоты)
Computer
22
(Компьютеры)
Computer
23
(Компьютеры)
Furnace
24
(Печи)
Дочерний
класс
Choke
(Дроссели)
Switch
(Выключатели)
Resistor
(Сопротивления)
Hydrochloric
(Соляная)
Perchloric
(Хлорная)
Gypsum
(Гипс)
Sulphuric
(Серная)
Formic
(Муравьиная)
Phosphoric
(Фосфорная)
Multiprocessor
(Многопроцессорный)
Notebook
(Ноутбук)
Gas
(Газовая)
-90-
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]