public class Employee {
// GiveBonus() имеет реализацию, заданную по умолчанию,
// но дочерние классы могут переопределить это поведение.
public virtualvoid GiveBonus(float amount) {currPay += amount;}
…
}
Чтобы в подклассе переопределить виртуальный метод, используется ключевое слово override. Например, SalesPerson и Manager могут переопределить GiveBonus() так, как показано ниже (мы предполагаем, что PTSalesPerson переопределяет GiveBonus() примерно так же, как SalesPerson),
public class SalesPerson: Employee {
// Премия продавца зависит от числа продаж.
public overridevoid GiveBonus(float amount) {
int salesBonus = 0;
if (numberOfSales ›= 0 && numberOfSales ‹= 100) salesBonus = 10;
else
if (numberOfSales ›= 101&& numberOfSales ‹= 200) salesBonus = 15;
else salesBonus = 20; // Вcе, что больше 200.
base.GiveBonus(amount * salesBonus) ;
}
}
public class Manager: Employee {
// Менеджер в дополнение к денежному вознаграждению
// получает некоторое число опционов.
public overridevoid GiveBonus(float amount) {
// Прибавка к зарплате.
base.GiveBonus(amount);
// И получение опционов…
Random r = new Random();
numberOfOptions += (ulong)r.Next(500);
}
…
}
Обратите внимание на то, что переопределенный метод будет использовать поведение, принятое по умолчанию, если указать ключевое слово base. При этом нет необходимости снова реализовывать логику GiveBonus(), а можно снова использовать (и, возможно, расширить) поведение родительского класса, принятое по умолчанию.
Также предположим, что Employee.DisplayStats() был объявлен виртуально и переопределен каждым подклассом, чтобы учесть число продаж (для продавцов) и текущее состояние опционов (для менеджеров). Теперь, когда каждый подкласс может по-своему интерпретировать виртуальные методы, каждый экземпляр объекта ведет себя более независимо.
static void Main (string[] args) {
// Лучшая система премиальных!
Manager chucky = new Manager("Chucky", 50, 92, 100000, "333-23-2322", 9000);
chucky. GiveBonus(300);
chucky.DisplayStats();
SalesPerson fran = new SalesPerson("Fran", 43, 93, 3000, "932-32-3232", 31);
fran. GiveBonus(200);
fran.DisplayStats();
}
Снова о ключевом слове sealed
Ключевое слово sealed может также применяться к членам типа, чтобы запретить переопределение таких виртуальных членив в производных типах. Это оказывается полезным тогда, когда нужно изолировать не весь класс, а только несколько его методов или свойств.
Например, если (по некоторой причине) классу PTSalesPerson требуется разрешить расширение другими классами, но нужно гарантировать, чтобы эти классы не могли переопределять виртуальный метод GiveBonus(), можно использовать следующий вариант программного кода.
// Этот класс можно расширить,
// но GiveBonus() не может переопределяться производным классом.
public class PTSalesPerson: SalesPerson {
…
public override sealed void GiveBonus(float amount) {
…
}
}
В данный момент базовый класс Employee скомпонован так, что он может поставлять своим потомкам защищенные члены-переменные, а также два виртуальных метода (GiveBonus() и DisplayStats()), которые могут переопределяться производным классом. Все это хорошо, но данный вариант программного кода имеет один недостаток: вы можете непосредственно создавать экземпляры базового класса Employee.
// Что же это значит?
Employee X = new Employee ();
В данном примере единственной целью базового класса Employee является определение общих полей и членов для всех подклассов. Вероятно, вы не предполагали, что кто-то будет непосредственно создавать экземпляры класса, поскольку тип Employee (работник) является слишком общим. Например, если я приду к вам и скажу "Я работаю!", то в ответ я, скорее всего, услышу вопрос "Кем вы работаете?" (консультантом, инструктором, ассистентом администратора, редактором, представителем Белого Дома и т.п.).
Ввиду того, что многие базовые классы оказываются чем-то вроде "небожителей", для нашего примера лучше всего запретить возможность непосредственного создания новых объектов Employee. В C# это можно сделать программными средствами, используя ключевое слово abstract.
// Обозначение класса Employee, как абстрактного,
// запрещает непосредственное создание его экземпляров.
Читать дальше