Главная · Карта сайта · Поиск · Статьи · Компьютерные курсы · Обучающие программы · Открытые проекты · Веб-программирование · Создание интернет-сайта · Полезные ссылки · Глоссарий · Контакты · Декабрь 06 2016 22:52:01
Последнее опубликованное

Что такое Model-View-Controller
Pattern Model-View-Controller

Как создать свой веб-сайт
Как создать свой сайт в интернете

Разное
Статистика

Программирование на C#. Переопределение не виртуального метода


[Назад] [Следующая страница]

1.3. Виртуальные и не виртуальные методы и способы их переопределения

Предположим, что существует некий компонент в нашей геоинформационной системе, который из внешнего источника загружает координаты точечных объектов, представленные в текстовом формате. Для работы с данными этого источника в классе PointGeometry был реализован метод Parse(). Позднее случилось так, что этот источник, помимо координат, стал поставлять еще и текст (подписи точек). Для обработки записей с текстом был разработан отдельный класс Label. По какой-то причине определение класса PointGeometry оказалось недоступным для редактирования, т.е. нет возможности объявить метод Parse() виртуальным, но необходимость в переопределении его поведения для класса Label осталась.

Для того чтобы сообщить компилятору, что метод Parse() в классе Label замещает одноименный метод в базовом классе, используется ключевое слово new в контексте определения метода. Из реализации метода Parse() в производном объекте можно вызвать базовую реализацию это метода с использованием ключевого слова base (фрагмент кода слева).

К сожалению, и это не решает проблему полностью, поскольку метод Parse() не попадает в таблицу виртуальных методов, и его переопределенная реализация будет вызвана только в случае использования ссылки на интерфейс класса Label (фрагмент кода справа). Переменная p и l ссылаются на экземпляр одного и того же типа (на объекты класса Label), но предоставляют доступ к нему посредством разных интерфейсов! Механизм виртуальных методов, независимо от текущего интерфейса, всегда обеспечивает вызов той реализации, которая определена для типа экземпляра. В случае с методом Clone() это означает, что в любом случае будет вызвана переопределенная в классе Label реализация. Если же метод не является виртуальным, то будет вызвана реализация текущего интерфейса. Следовательно, приведя объект класса Label к интерфейсу базового класса PointGeometry, при вызове метода Parse() мы вызовем реализацию, определенную для класса PointGeometry, а не для класса Label.

Если класс Label, по мнению архитекторов программы, является конечным звеном в цепи эволюции типов Geometry2D, то его следует сопроводить модификатором sealed. Такое решение огорчит тех, кто пожелает определить производный от Label класс. Модификатор sealed также может применяться к методам и свойствам, например, вместе с модификатором override, когда необходимо запретить дальнейшее переопределение виртуального метода в производных классах.

using System;
namespace CSharpQuickGuide
{
    //Класс 'текстовая метка'
    //Ключевое словое sealed говорит о том, что
    //класс Label не может иметь производных классов
    sealed public class Label : PointGeometry 
    {
        //Подпись точечной геометрии
        private string m_Text = string.Empty;
        //Свойство 'подпись'
        public string Text
        {
            get { return m_Text; }
            set { m_Text = value; }
        }

        //Конструктор по умолчанию
        public Label()
            : base() {}
        //Конструктор с параметрами
        public Label(Point2D _Point, string _Text)
            : base(_Point) { m_Text = _Text; }
        //Переопределение функции клонирования
        public override Geometry2D Clone()
        {
            //реализация отсутствует
            throw new NotImplementedException();
        }
        //Переопределение невиртуального метода Parse
        //с использованием ключевого слова new
        public new void Parse(string _Geometry)
        {
            //Вызов базовой реализации Parse
            //для извлечения координат и ориентации
            //точечной геометрии: 
            //PointGeometry.Parse(_Geometry)
            base.Parse(_Geometry);

            //Извлечение из _Geometry значения Text
            //(реализация отсутствует);
        }
    }
}
using System;
namespace CSharpQuickGuide
{
    static class Application
    {
        static void Main()
        {
            //Ссылка на интерфейс базового класса
            PointGeometry p = new Label();
            //Ссылка на интерфейс Label
            Label l = new Label();

            //Функция Clone() - виртуальная функция!
            //Вызов реализации Label
            p.Clone();
            //Вызов реализации Label
            l.Clone();

            string _Geometry;
            _Geometry = "X=15.2;Y=23.4;Text='Label'";

            //Метод Parse НЕ является виртуальным
            //Вызов реализации PointGeometry!
            p.Parse(_Geometry);
            //Вызов реализации Label!
            l.Parse(_Geometry);
        }
    }
}


[Назад] [Следующая страница]

Компьютерные курсы и курсы программирования
Основы программирования

Курс для начинающих программистов на C# и VB.NET.

SQL 25™

Построение SQL запросов и работа с базой данных.

C# Quick Guide™

Программирование на C#. Краткое руководство.

RegEx

Применение регулярных выражений.

Plug-in архитектура

Примеры программной Plug-in архитектуры.

XML и его расширения

Язык разметки XML и его расширения с примерами.

HTML и разметка гипертекста

Языки HTML, XHTML и CSS с примерами разметки.

Основы веб-дизайна

Основы веб-дизайна: решения типовых задач верстки.

Программирование на PHP

Руководство по программированию на PHP для начинающих.

Справочные материалы

Шаблоны проектирования
Каталог шаблонов проектирования программных компонентов.

Рефакторинг кода
Каталог приемов рефакторинга программного кода.

Гость
Имя

Пароль



Забыли пароль?
Запросите новый здесь
.
Coding Craft. Все права защищены © 2011. Проект Инициативного Народного Фронта Образования - ИНФО-проект.