лекции (2010) (by Ульянов Алексей_ Лихогруд Николай_ Сергеев Николай) (1160852), страница 14
Текст из файла (страница 14)
В итогеполучаем N множеств возможных функций.II. Ищем пересечение этих множеств. Если оно пусто, то нет подходящей функции. Если пересечениесодержит 2 или более элемента, то неоднозначность. Но если там одна функция, она и обслужит вызов.Пример.class X { public: X (int); ... };class Y { ... };void f (X, int);/* 1 */void f (X, double);/* 2 */void f (Y, double);/* 3 */Пусть мы вызываем f(1,5);. По первому параметру мы оставляем 1 и 2 (пользовательскиепреобразования), по второму – 1 (точное соответствие). Пересечение даёт первый вариант.Теперь попробуем вызвать f(1,5.0);.
По первому параметру мы оставляем 1 и 2 (пользовательскиепреобразования), по второму – 2 и 3 (точное соответствие). Пересечение даёт второй вариант.Пример на *пятый шаг*.class R { public: R (double); ... };void f (int, R);void f (int, ...);void g () {f (1, 1);// первый обработчикf (1, “preved!”);// второй обработчик}Нужно сделать еще одно замечание, касающееся описанного алгоритма. Как определить, какие именнофункции попадают в множество “испытуемых”? Ответ таков: все функции с таким именем, которые могутбыть вызваны с таким набором фактических параметров. Это правило кажется тривиальным, однако ономожет помочь в ситуации, когда у некоторых функций есть значения по умолчанию, а у некоторых - '...' всписке параметров.Скрытие: скрытие происходит при наследовании, в унаследованном классе, если в производномклассе есть такое же имя как в базовом.
Этот случай надо отличать от последнего, так как в последнем тожесовпадают имена, но там за дело берётся виртуальность.Переопределение: в переопределении главная роль уделяется виртуальным функциям, собственно впереопределении и заключен весь механизм работы виртуальных функций.Механизм виртуальных функций.Чтобы включился механизм виртуализации, должны быть выполнены следующие требования:•присутствует иерархия классов;•в базовом классе функция объявлена как виртуальная;•в производном классе описана функция с таким же профилем (совпадают имя, список параметров сточностью до имён и тип результата);•используется вызов функции через указатель (без уточнения с помощью оператора разрешенияконтекста ::).Однако к этим четырём заповедям нужно прибавить ещё некоторые замечания:•Если описывать функцию вне класса, то в её профиле virtual не повторяют.
В описании функции впроизводном классе также можно указать virtual, но это ни на что не повлияет, разве что нанаследство производного.•Тип результата может слегка отличаться. Если в базовом классе виртуальная функция возвращаетуказатель на базовый класс, то в производном она имеет право возвращать указатель на производныйкласс (то же со ссылками).•Если списки параметров совпадают, а типы результата существенно отличаются, мы получимсинтаксическую ошибку.•Если списки параметров различаются, то функция из производного класса скрывает функцию избазового, виртуальность не работает, и при вызове через указатель получаем статическоеопределение по типу указателя.•Если в производном классе вообще нет функции с таким именем, то метод полностью наследуется, тоесть мы сможем использовать виртуальность во внуке, а сын (производный класс) просто получит всвое распоряжение эту функцию.•Если вызываем метод через объект (h.print()), то виртуальность не работает, статическоеопределение по типу объекта, от которого его вызываем.•При явном указании класса виртуальность не работает, даже если функция вызвана через указатель,то есть pp->Person::print(); – статическое определение.Замечание: В Java, Delphi также имеется синтаксическая конструкция virtualЗамечание: Головин сказал, что можно считать, что вызов через ссылку или указатель всегда виртуальныйЗамечание: Если виртуальная функция возвращает один из базовых типов языка, то тип возвращаемогозначения у замещающей функции должен совпадать с типом замещаемой функции.
В случае если онавозвращает объект класса, то при переопределении может возвращаться производный от него тип.Замечание: Если открытая функция переопределена как приватная, то она может быть вызвана изинтерфейса базового классаЗамечание: В С++ нет никаких ограничений с точки зрения наследования, то есть нет никаких языковыхметодов запретить наследования данного класса. В Java можно запретить наследование с помощьюключевого слова final. Если это слово стоит перед именем метода, то этот метод не может переопределяться впроизводных классах. Если же оно стоит перед определением класса, то класс нельзя наследовать. В C# такуюроль играет sealed.Рассмотрим ситуацию наследования в языках C#, Delphi. Как и в С++, там есть виртуальные методы.
Если вклассе метод объявлен как виртуальный, то в классе наследнике возможна ситуация – есть функция, укоторой совпадает профиль, имя, параметры, но она не замещает функцию из базового класса. Разработчикиввели специальный модификатор override – для того чтобы функция действительна замещала.Поговорим немножко о реализации виртуальности на примере С++. Разобраться в этом нам поможетотрывок из книжки «Дизайн и эволюция языка С++»:Теперь пришло время рассмотреть как обстоят дела в модульных языках:Ада, Оберон:MODULE M;TYPE BASE = RECORDI : INTEGERJ: REALEND;ENDM;MODULE M1;IMPORT M:TYPE DERIVED = RECORD(BASE)K:INTEGERENDPROCEDURE P(VAR X:DERIVED)Существуют только лишь либо публичные члены, либо пакетные, а как таковых защищенных иприватных нет.Package M is type base is tagged private;…Private type Base is tagged record…end recordend M;Package M1 is use M;Type Derived is new Base with recordK:integer;End recordProcedure B(x:inout Derived) is…В Аде появляется понятие дочерних пакетов.Package M.M1 is …Type Derived is new Base with recprdK:integerend recordprocedure P(x : inout Derived)Множественное наследование.Множественное наследование - ситуация, когда производный класс создаётся на базе нескольких базовыхклассов.
Как было сказано выше из всех проходимых нами языков, множественное наследованиереализовано только в С++, поэтому примеры ниже будут написаны на С++Чтобы понять, зачем это нужно, можно привести пример от Бьярна Страуструпа. При программированиинекого GUI у нас есть класс ‘окно’. От него есть производные классы: ‘окно с рамкой’ и ‘окно с меню’. А чтоесли мы хотим создать окно с рамкой и с меню? Нам на помощь приходит множественное наследование.Пример. Далее приведём чисто технический пример, который не несёт никакой смысловой нагрузки, но накотором можно показать синтаксис.class A { ...
};class B { ... };class C: public A, public B { ... };Базовый класс не может появиться несколько раз в этом списке явно (ситуация ‘одна база – два раза’). Однакоможет возникнуть такая ситуация:class L { public: int n; ... };class A: public L { ... };class B: public L { ... };class C: public A, public B { ... };AnBnCLLABCрешёткасмежностиНапример, мы напишем: C.c; c.n = 0; Возникает неоднозначность: какую c нам вызвать, ту котораяпришла к нам через A, или же ту, которая наследовалась через B.
Здесь мы можем уточнить: c.A::n = 5;или c.B::n = 7;. Перед оператором разрешения контекста мы указываем точку, от которой начинаетсяпоиск переменной.Замечание: в других языках тоже существует оператор уточнения (x::N ~ super.N ~ base.N ~ inherited.N)Лекция. Лихогруд Н.Н.Абстрактные классы и интерфейсыСами по себе иерархии классов бесполезны, если в них нету динамически связанных методов.•••Если существуют признаки, общие для всех объектов в класса иерархии, то эти признакицелесообразно поместить в базовый классУ каждого объекта класса имеется состояние (текущие значения параметров) и поведение (методыкласса)Некоторая функциональность (особенности поведения), общая для всех классов в иерархии, можетбыть реализована только при дальнейшей детализации в производных классах.=> приходим к понятию абстрактного базового классаВ языках Delphi, Оберон-2, TP 5.5, C++, Java, C# имеется языковая поддержка абстрактных классов.Пример:Figure – абстрактная фигураОбщие данные – (x,y) – координаты фигурыОбщие методы – Draw(), Move() – не могут быть реализованы для абстрактной фигурыЧто будет если просто не определить витуальную функцию в базовом классе:Полиморфный класс – класс, в котором есть виртуальные функции (и.