Опубликован: 19.08.2004 | Уровень: для всех | Доступ: платный | ВУЗ: Национальный исследовательский ядерный университет «МИФИ»

Лекция 10: Концепция полиморфизма и ее реализация в языке C#

Рассмотрим более подробно особенности стратегии вычислений с вызовом по значению (call-by-value, CBV).

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

Кроме того, фактический параметр в случае вызова по значению является выражением.

Проиллюстрируем особенности использования стратегии вызова по значению следующим фрагментом программы на языке C#:

void Inc(int x) {
    x = x + 1;
}
void f() {
    int val = 3;
    Inc(val);
    // val == 3
}

Как видно из приведенного примера, фрагмент программы на языке C# реализует ввод значений val посредством функции f. Функция Inc является функцией следования (т.е. прибавления единицы для целых чисел).

Отметим, что, несмотря на применение функции Inc к аргументу val, значение переменной val, как явствует из комментария

// val == 3,

остается неизменным. Это обусловлено тем, что при реализации стратегии вызова по значению формальный параметр является копией фактического.

Рассмотрим более подробно особенности стратегии вычислений с вызовом по имени, или, иначе, по ссылке (call-by-reference, CBR).

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

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

Проиллюстрируем особенности использования стратегии вызова по имени следующим фрагментом программы на языке C#:

void Inc(ref int x) {
    x = x + 1;
}
void f() {
    int val = 3;
    Inc(ref val);
    // val == 4
}

Как видно из приведенного примера, фрагмент программы на языке C# реализует преобразование значений val посредством функции f. Функция Inc является функцией следования.

Отметим, что вследствие применения функции Inc к аргументу val, значение переменной val, как явствует из комментария

// val == 4,

изменяется. Это обусловлено тем обстоятельством, что при реализации стратегии вызова по имени формальный параметр является подстановкой фактического.

Рассмотрим более подробно особенности стратегии вычислений с вызовом по необходимости (call-by-need, CBN).

В целом, данная стратегия вычислений сходна с вызовом по имени (или ссылке, call-by-reference, CBR), однако ее реализация имеет две характерные особенности.

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

Во-вторых, данная стратегия вычислений неприменима до того, как означивание может быть произведено, т.е. значение фактического параметра может быть вычислено.

Проиллюстрируем особенности использования стратегии вызова по необходимости следующим фрагментом программы на языке C#:

void Read (out int first, out int next) {
    first = Console.Read();
    next = Console.Read();
}
void f() {
    int first, next;
    Read(out first, out next);
}

Как видно из приведенного примера, фрагмент программы на языке C# реализует ввод значений first и next посредством функции Read со стандартного устройства ввода. Функция f может быть означена по необходимости, по мере поступления аргументов.

Исследовав особенности реализации различных стратегий вычислений в языке программирования C#, рассмотрим концепцию полиморфизма в соотнесении с механизмом так называемых абстрактных классов.

Абстрактные классы при объектно-ориентированном подходе (в частности, в языке программирования C#) являются аналогами полиморфных функций в языках функционального программирования (в частности, в языке SML) и используются для реализации концепции полиморфизма . Методы, которые реализуют абстрактные классы, также называются абстрактными и являются полиморфными.

Перечислим основные особенности, которыми обладают абстрактные классы и методы в рамках объектно-ориентированного подхода к программированию.

Прежде всего, отметим то обстоятельство, что абстрактные методы не имеют части реализации (implementation).

Кроме того, абстрактные методы неявно являются виртуальными (т.е. как бы оснащенными описателем virtual ).

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

Наконец, в языке программирования C# запрещено создание объектов абстрактных классов (как конкретизаций или экземпляров ).

Проиллюстрируем особенности использования абстрактных классов следующим фрагментом программы на языке C#:

abstract class Stream {
    public abstract void 
        Write(char ch);
    public void WriteString(string s)
    { 
        foreach (char ch in s) 
            Write(s);
    }
}

class File : Stream {
    public override void Write(char ch)
    {
        ...
        write ch to disk
        ...
    }
}

Как видно из приведенного примера, фрагмент программы на языке C# представляет собой описание абстрактных классов Stream и File, реализующих потоковую запись (метод Write ) данных в форме символьных строк ch.

Заметим, что описание абстрактного класса Stream реализовано явно посредством зарезервированного слова abstract. Оператор foreach ... in реализует последовательную обработку элементов.

Необходимо обратить внимание на то обстоятельство, что поскольку в производных классах необходимо замещение методов, метод Write класса File оснащен описателем override.

Подводя итоги рассмотрения основных аспектов концепции полиморфизма в объектно-ориентированном подходе к программированию и особенностей реализации этой концепции применительно к языку программирования C#, кратко отметим достоинства полиморфизма.

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

Кроме того, важным практическим следствием реализации концепции полиморфизма для экономики программирования является снижение стоимости проектирования и реализации программного обеспечения.

Еще одно достоинство полиморфизма - возможность усовершенствования стратегии повторного использования кода. Код с более высоким уровнем абстракции не требует существенной модификации при адаптации к изменившимся условиям задачи или новым типам данных.

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

Наконец, концепция полиморфизма является достаточно универсальной и в равной степени применима для различных подходов к программированию, включая функциональный и объектно-ориентированный.

Для более подробного самостоятельного ознакомления с тематикой лекции рекомендуется следующий список источников: [ 23, 26, 53, 59, 62, 63, 74-76].