Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП.doc
Скачиваний:
1
Добавлен:
24.09.2019
Размер:
522.24 Кб
Скачать

Вопрос 8) Полиформизм, перегрузка методов

В предыдущих статьях мы поговорили с вами о наследовании и инкапсуляции. В данной статье мы познакомимся с полиморфизмом, который является неотъемлемой частью объектно-ориентированного языка программирования, коим является C#.

Как и наследование, полиморфизм имеет две разновидности: классический полиморфизм и полиморфизм ad hoc. Полиморфизм весьма удобная и полезная вещь, но, к сожалению, ей пользуются гораздо реже чем инкапсуляцией и наследованием. Полиморфизм очень похож на проектирование. Все осознают, что проектирование весьма полезно и необходимо, но вот почему-то от него отказываются. Полиморфизм позволяет обозначить функциональность вашего будущего приложения, не реализовывая ее. Каким образом это делается читайте дальше.

Давайте вернемся к иерархии классов, которую мы рассматривали в предыдущей статье "Наследование в C#". Давайте предположим, что мы хотим реализовать метод GiveMoney() (выдать заработную плату). Мы с вами точно знаем, что у классов "Учитель" и "Водитель" должен быть такой метод, ведь оба должны получать деньги за свой труд. Более того мы даже знаем что у любого рабочего должна быть зарплата. Но проблема в том, что зарплата бывает разная. Бывает повременная работа, сдельная, премиальная и т.д. Т.е. учителю мы будем платить в зависимости от отработанных часов и стажа, а водителю в зависимости от километража. Иными словами наш метод GiveMoney() в каждом классе должен быть разный, но выполнять одну и ту же функцию, а именно, начислять заработную плату. Данная проблема решается как раз с помощью полиморфизма.

Реализуется полиморфизм очень легко. Во-первых, нам необходимо сообщить, что во всех наследуемых от класса "Рабочий" классах должен поддерживаться метод GiveMoney(). Во-вторых, мы должны в каждом наследуемом классе реализовать метод GiveMoney(). Делается это достаточно просто. Необходимо воспользоваться двумя словами: virtual и override. Вот как это выглядит для нашего случая:

public class Worker : Man

{

//Виртуальный метод

public virtual void GiveMoney(int money)

{

Console.WriteLine("Получите "+money+" рублей");

}

}

public class Teacher : Worker

{

//Задаем необходимую функциональность

public override void GiveMoney(int money)

{

int bonus = 1000; //премиальные 1000 руб

money = money + bonus;

base.GiveMoney(money);

}

}

Перед вами два класса. Класс Teacher (Учитель) наследуется от класса Worker (Рабочий). В базовом классе Worker мы создали метод GiveMoney(), и определили его работоспособность по умолчанию. Обратите внимание на ключевое слово virtual. Таким образом наш метод стал виртуальным, а это означает, что он может быть переопределен в наследуемом классе, а может быть и не переопределен. В классе Teacher мы переопределяем метод GiveMoney() с помощью ключевого слова override. Здесь мы немного изменили логику. Учитель кроме зарплаты будет получать еще и премию в размере 1000 рублей. Все это для простоты примера. Логика может быть любой, решать вам. Обратите внимание на то, что мы используем метод GiveMoney() базового класса с помощью указателя base. В принципе это делать не обязательно, но это избавит вас от лишнего копирования кода.

Вот так и работает полиморфизм. Но этим конечно полиморфизм не ограничивается. Говоря о полиморфизме необходимо затронуть понятие "Абстрактный класс" и "Абстрактный метод". Как вы помните, я сказал что виртуальные функции можно переопределять, а можно и не переопределять. Что делать если необходимо быть уверенным, что в наследуемом классе метод будет переопределен? Для этого существует понятие "Абстрактный метод", в языке C++ такие методы называются чисто виртуальными (если я не ошибаюсь). Но для того, чтобы говорить об абстрактных методах нужно сперва объяснить, что такое абстрактные классы, т.к. абстрактные методы могут быть только у абстрактных классов (в этом предложении я 4 раза употребил слово "абстрактный", уж простите).

Итак, если вы объявите класс абстрактным, то создавать объекты данного класса будет невозможно, зато можно производить наследование от данного класса. Это такая своеобразная защита, которая имеет и другое назначение. С помощью абстрактных классов и методов мы проектируем будущую структуру нашего приложения. Объявить класс абстрактным можно с помощью слова abstract:

absract public class Worker : Man

{

...

}

Таким образом наш класс Worker стал абстрактным, т.е. рабочих у нас теперь не будет, оно и верно. После того, как мы создали абстрактный класс можно и поговорить об абстрактных методах. Делая метод абстрактным, вы тем самым принуждаете наследуемый класс переопределить данный метод и если он этого не сделает, то ему будет плохо (точнее плохо будет программисту, т.к. компилятор заругается и откажется компилировать). Более того, поскольку вы теперь уверены, что ваш метод будет 100% переопределен, то вы можете даже не реализовывать эти методы в базовом классе. Для нашего случая с "Рабочим" и "Учителем" очень хорошо подходит использование абстрактных классов и методов. Вот как это будет выглядеть:

abstract public class Worker : Man

{

//абстрактный метод

public abstract void GiveMoney(int money);

}

public class Teacher : Worker

{

//обязательно переопределяем метод

public override void GiveMoney(int money)

{

int bonus = 1000;

money = money + bonus;

Console.WriteLine("Получите "+money+" рублей");

}

}

Обратите особое внимание на класс Worker и на абстрактный метод GiveMoney().

Давайте рассмотрим еще один интересный случай. Допустим вы захотите запретить наследование не всех методов а только одного. Сделать это невозможно, но есть другой выход из этой ситуации. Этот способ называется контролем версий. Он заключается в том, что вы можете переопределить любой метод (а точнее создать новый с таким же именем), вне зависимости от того является он виртуальным или нет. Для этого нужно объявить метод с ключевым словом new. Контроль версий чрезвычайно полезная и занимательная вещь. С помощью приведения типов можно обращаться к методу базового класса. Т.е. возникает иллюзия того, что у класса 2 метода с одним и тем же именем. Но чаще всего это ведет к путанице.

Еще хотелось бы сказать о втором виде полиморфизма. Заключается он в том, что у нескольких не связанных между собой классов могут быть методы со схожим назначением и с одинаковыми именами. Т.е. вы можете смело вызывать этот метод не задумываясь о классе, а система уже сама решит какую именно реализацию надо вызывать. В общем, как и наследование has-a, полиморфизм ad hoc вещь весьма не очевидная.

На последок хотелось бы добавить, что привыкать к полиморфизму (как и к проектированию) нужно с самого начала, а то потом будет поздно.

Вопрос 9) Принцип наследования. Виртуальные и абстрактные методы

Наследованием называется возможность порождать один класс от другого с сохранением всех свойств и методов класса-предка (прародителя, иногда его называют суперклассом) и добавляя, при необходимости, новые свойства и методы. Набор классов, связанных отношением наследования, называют иерархией. Наследование призвано отобразить такое свойство реального мира, как иерархичность.

Механизмы наследования

Объявление класса в языке C# создает новый ссылочный тип, определяющий как описание методов, так и их реализацию.

Объявление интерфейса создает новый ссылочный тип, который специфицирует описание методов и имена некоторых констант, но не определяет саму реализацию.

Интерфейс может быть объявлен для расширения одного или нескольких интерфейсов.

Наследование позволяет определять новые классы в терминах существующих классов. В языке C# поддерживается только простое наследование: любой подкласс является производным только от одного непосредственного суперкласса. При этом любой класс может наследоваться от нескольких интерфейсов.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]