Выбрать главу

public override void VirtMethod()

{

     Console.WriteLine("внук: " + this.ToString ());

}

В классе Found определены два невиртуальных метода Nonvirtmethod и Work, наследуемые потомками Derived и ChildDerived без всяких переопределений. Вы ошибаетесь, если думаете, что работа этих методов полностью определяется базовым классом Found. Полиморфизм делает их работу куда более интересной. Давайте рассмотрим в деталях работу метода Work;

public void Work()

{

    VirtMethod();

    NonVirtMethod();

    Analysis ();

}

При компиляции метода work будет обнаружено, что вызываемый метод VirtMethod является виртуальным, поэтому для него будет применяться динамическое связывание. Это означает, что вопрос о вызове метода откладывается до момента, когда метод Work будет вызван объектом, связанным с х. Объект может принадлежать как классу Found, так и классам Derived и ChildDerived, в зависимости от класса объекта и будет вызван метод этого класса.

Для не виртуальных методов NonvirtMethod и Analysis будет применено статическое связывание, так что work всегда будет вызывать методы, принадлежащие классу Found. Однако и здесь не все просто. Метод NonVirtMethod

public void NonVirtMethod()

{

    Console.WriteLine ("Мать: "+ this.ToString ());

}

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

Что же касается метода Analysis, определенного в каждом классе, то всегда в процессе работы work будет вызываться только родительский метод анализа из-за стратегии статического связывания.

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

Класс Found, создающий метод Work, говорит примерно следующее: "Я предоставляю этот метод своим потомкам. Потомок, вызвавший этот метод, должен иметь VirtMethod, выполняющий специфическую для потомка часть работы; конечно, потомок может воспользоваться и моей реализацией, но допустима и его собственная реализация. Затем часть работы выполняю я сам, но выдача информации об объекте определяется самим объектом. Заключительную часть работы, связанную с анализом, я потомкам не доверяю и делаю ее сам".

Пример работы с полиморфным семейством классов

Классы семейства с полиморфными методами уже созданы. Давайте теперь в клиентском классе Testing напишем метод, создающий объекты наших классов и вызывающий методы классов для объектов семейства:

public void TestFoundDerivedReal ()

{

    Found bs = new Found ("father", 777);

    Console.WriteLine("Объект bs вызывает методы класса Found");

    bs.VirtMethod();

    bs.NonVirtMethod ();

    bs.Analysis(); bs.Work();

    Derived der = new Derived("child", 888, 555);

    Console.WriteLine("Объект der вызывает методы класса Derived");

    der.DerivedMethod();

    der.VirtMethod();

    der.NonVirtMethod ();

    der.Analysis();

    der.Work();

    ChildDerived chider = new ChildDerived("grandchild", 999, 444);

    Console.WriteLine("Объект chider вызывает методы ChildDerived");

    chider.VirtMethod();

    chider.NonVirtMethod();

    chider.Analysis(5);

    chider.Work();

}

Результаты работы этого метода изображены на рис. 18.3.

Рис. 18.3. Полиморфизм семейства классов

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

Абстрактные классы

С наследованием тесно связан еще один важный механизм проектирования семейства классов — механизм абстрактных классов. Начну с определений.

Класс называется абстрактным, если он имеет хотя бы один абстрактный метод.

Метод называется абстрактным, если при определении метода задана его сигнатура, но не задана реализация метода.