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

Статическим связыванием называется связывание цели вызова и вызываемого метода на этапе компиляции, когда с сущностью связывается метод класса, заданного при объявлении сущности.

Динамическим связыванием называется связывание цели вызова и вызываемого метода на этапе выполнения, когда с сущностью связывается метод класса объекта, связанного с сущностью в момент выполнения.

При статическом связывании метод выбирается из класса сущности, при динамическом — из класса объекта, связанного с сущностью. Понятно, что на этапе компиляции возможно только статическое связывание, поскольку только в период выполнения можно определить, с объектом какого класса связана данная сущность. Это может быть класс любого из потомков класса сущности.

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

Уже достаточно давно разработан эффективный механизм реализации динамического связывания. Еще на этапе компиляции подготавливается так называемая таблица виртуальных методов, содержащая их адреса. Связывание объекта хk с принадлежащим ему методом Mk производится выбором соответствующего элемента из этой таблицы и выполняется ненамного сложнее, чем получение по индексу соответствующего элемента массива.

В языке C# принята следующая стратегия связывания. По умолчанию предполагается статическое связывание. Для того чтобы выполнялось динамическое связывание, метод родительского класса должен снабжаться модификатором virtual или abstract, а его потомки должны иметь модификатор override.

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

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

В основе полиморфизма, характерного для семейства классов, лежат три механизма:

• одностороннее присваивание объектов внутри семейства классов; сущность, базовым классом которой является класс предка, можно связать с объектом любого из потомков. Другими словами, для введенной нами последовательности объектов хk присваивание xi = xj допустимо для всех j >=i;

• переопределение потомком метода, наследованного от родителя. Благодаря переопределению, в семействе классов существует совокупность полиморфных методов с одним именем и сигнатурой;

• динамическое связывание, позволяющее в момент выполнения вызывать метод, который принадлежит целевому объекту.

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

Вернемся к нашему примеру с классами Found, Derived, chiidDerived. Напомню, в родительском классе определен виртуальный метод 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 переопределяется: