Например, если (по некоторой причине) классу PTSalesPerson требуется разрешить расширение другими классами, но нужно гарантировать, чтобы эти классы
// Этот класс можно расширить,
// но GiveBonus() не может переопределяться производным классом.
public class PTSalesPerson: SalesPerson {
…
public override sealed void GiveBonus(float amount) {
…
}
}
Абстрактные классы
В данный момент базовый класс Employee скомпонован так, что он может поставлять своим потомкам защищенные члены-переменные, а также два виртуальных метода (GiveBonus() и DisplayStats()), которые могут переопределяться производным классом. Все это хорошо, но данный вариант программного кода имеет один недостаток: вы можете непосредственно создавать экземпляры базового класса Employee.
// Что же это значит?
Employee X = new Employee ();
В данном примере единственной целью базового класса Employee является определение общих полей и членов для всех подклассов. Вероятно, вы не предполагали, что кто-то будет непосредственно создавать экземпляры класса, поскольку тип Employee (работник) является слишком общим. Например, если я приду к вам и скажу "Я работаю!", то в ответ я, скорее всего, услышу вопрос
Ввиду того, что многие базовые классы оказываются чем-то вроде "небожителей", для нашего примера лучше всего
// Обозначение класса Employee, как абстрактного,
// запрещает непосредственное создание его экземпляров.
abstract public class Employee {…}
Если вы теперь попытаетесь создать экземпляр класса Employee, то получите ошибку компиляции.
// Ошибка! Нельзя создать экземпляр абстрактного класса.
Employee X = new Employee();
Превосходно! К этому моменту мы построили очень интересную иерархию служащих. Мы добавим новые функциональные возможности в это приложение немного позже, когда будем рассматривать правила классификации в C#. Иерархия типов, определенных на данный момент, показана на рис. 4.9.
Исходный код. Проект Employees размещен в подкаталоге, соответствующем главе 4.
Принудительный полиморфизм: абстрактные методы
Если класс является абстрактным базовым классом, он может определять любое число
Рис. 4.9. Полная иерархии служащих
Рис. 4.10. Иерархия форм
Как и в случае иерархии служащих, лучше запретить пользователю объекта создавать экземпляры Shape (форма) непосредственно, поскольку соответствующее понятие слишком абстрактно. Для этого необходимо определить тип Shape, как абстрактный класс.
namespace Shapes {
public abstract class Shape {
// Форме можно назначить понятное имя.
protected string petName;
// Конструкторы.
public Shape()(petName = "БезИмени";}
public Shape(string s) (petName = s;}
// Draw() виртуален и может быть переопределен.
public virtual void Draw() {
Console.WriteLine("Shape.Draw()");
}
public string PetName {
get { return petName; }
set { petName = value; }
}
}
// Circle не переопределяет Draw().
public class Circle: Shape {
public Circle() {}
public Circle(string name): base(name) {}
}
// Hexagon переопределяет Draw().
public class Hexagon: Shape {