logo
C#, 320 стр

Три механизма, обеспечивающие полиморфизм

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

В совокупности это и называется полиморфизмом семейства классов. Целевую сущность часто называют полиморфной сущностью, вызываемый метод - полиморфным методом, сам вызов - полиморфным вызовом.

Вернемся к нашему примеру с классами Found, Derived, ChildDerived. Напомню, в родительском классе определен виртуальный метод VirtMethod и переопределен виртуальный метод ToString родительского класса object. Потомок класса Found - класс Derived переопределяет эти методы:

public override void VirtMethod()

{

Console.WriteLine("Сын: " + this.ToString());

}

public override string ToString()

{

return(String.Format("поля: name = {0},

credit = {1},debet ={2}",name, credit, debet));

}

Потомок класса Derived - класс ChildDerived не создает новых полей. Поэтому он использует во многом методы родителя. Его конструктор состоит из вызова конструктора родителя:

public ChildDerived(string name, int cred, int deb):base (name,cred, deb)

{}

Нет и переопределения метода Tostring, поскольку используется реализация родителя. А вот метод VirtMethod переопределяется:

public override void VirtMethod()

{

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

}

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

public void Work()

{

VirtMethod();

NonVirtMethod();

Analysis();

}

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

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

public void NonVirtMethod()

{

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

}

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

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

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

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