Страница 167 из 502
<b> }</b>
<b> // Сконструировать копию объекта типа Triangle, </b>
<b> public Triangle(Triangle ob) : base(ob) {</b>
<b> Style = ob.Style;</b>
<b> }</b>
<b> // Переопределить метод Area() для класса Triangle, </b>
<b> public override double Area() {</b>
<b> return Width * Height / 2;</b>
<b> }</b>
<b> // Показать тип треугольника, </b>
<b> public void ShowStyle() {</b>
<b> Console.WriteLine("Треугольник " + Style);</b>
<b> }</b>
<b>}</b>
<b>// Класс для прямоугольников, производный от класса TwoDShape </b>
<b>class Rectangle : TwoDShape {</b>
<b> // Конструктор для класса Rectangle, </b>
<b> public Rectangle(double w, double h) </b>
<b> : base(w, h, "прямоугольник"){ }</b>
<b> // Сконструировать квадрат, </b>
<b> public Rectangle(double x) : base (x, "прямоугольник") { }</b>
<b> // Сконструировать копию объекта типа Rectangle, </b>
<b> public Rectangle(Rectangle ob) : base(ob) { }</b>
<b> // Возвратить логическое значение true, если </b>
<b> // прямоугольник окажется квадратом, </b>
<b> public </b><b>bool IsSquare() {</b>
<b> if(Width == Height) return true; </b>
<b> return false;</b>
<b> }</b>
<b> // Переопределить метод Area() для класса Rectangle, </b>
<b> public override double Area() { </b>
<b> return Width * Height;</b>
<b> }</b>
<b>}</b>
<b>class AbsShape {</b>
<b> static void Main() {</b>
<b> TwoDShape[] shapes = new TwoDShape[4];</b>
<b> shapes[0] = new Triangle("прямоугольный", 8.0, 12.0); </b>
<b> shapes[1] = new Rectangle(10) ;</b>
<b> shapes[2] = new Rectangle(10, 4); </b>
<b> shapes[3] = new Triangle(7.0);</b>
<b> for(int i=0; i < shapes.Length; i++) {</b>
<b> Console.WriteLine("Объект — " + shapes[i].name);</b>
<b> Console.WriteLine("Площадь равна " + shapes[i].Area());</b>
<b> Console.WriteLine() ;</b>
<b> }</b>
<b> }</b>
<b>}</b>
Как показывает представленный выше пример программы, во всех производных классах метод Area() должен быть непременно переопределен, а также объявлен абстрактным. Убедитесь в этом сами, попробовав создать производный класс, в котором не переопределен метод Area(). В итоге вы получите сообщение об ошибке во время компиляции. Конечно, возможность создавать ссылки на объекты типа TwoDShape по-прежнему существует, и это было сделано в приведенном выше примере программы, но объявлять объекты типа TwoDShape уже нельзя. Именно поэтому массив shapes сокращен в методе Main() до 4 элементов, а объект типа TwoDShape для общей двухмерной формы больше не создается.
Обратите также внимание на то, что в класс TwoDShape по-прежнему входит метод ShowDim() и что он не объявляется с модификатором abstract. В абстрактные классы вполне допускается (и часто практикуется) включать конкретные методы, которые могут быть использованы в своем исходном виде в производном классе. А переопределению в производных классах подлежат только те методы, которые объявлены как abstract.
Предотвращение наследования с помощью ключевого слова sealed
Несмотря на всю эффективность и полезность наследования, иногда возникает потребность предотвратить его. Допустим, что имеется класс, инкапсулирующий последовательность инициализации некоторого специального оборудования, например медицинского монитора. В этом случае требуется, чтобы пользователи данного класса не могли изменять порядок инициализации монитора, чтобы исключить его неправильную настройку. Но независимо от конкретных причин в C# имеется возможность предотвратить наследование класса с помощью ключевого слова sealed.
Для того чтобы предотвратить наследование класса, достаточно указать ключевое слово sealed перед определением класса. Как и следовало ожидать, класс не допускается объявлять одновременно как abstract и sealed, поскольку сам абстрактный класс реализован не полностью и опирается в этом отношении на свои производные классы, обеспечивающие полную реализацию.
Ниже приведен пример объявления класса типа sealed.