лекции (2011), страница 8
Описание файла
Документ из архива "лекции (2011)", который расположен в категории "". Всё это находится в предмете "языки программирования" из 7 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Онлайн просмотр документа "лекции (2011)"
Текст 8 страницы из документа "лекции (2011)"
Java: class Derived extends Base {
// определение новых членов }
Java использует слово extends для выражения единственного типа наследования, соответствующего публичному наследованию в C++. Java не поддерживает множественное наследование. Классы Java тоже происходят от общего базового класса.
Oberon, Object Pascal, Turbo Pascal:
TYPE Derived = RECORD (Base)
// определение новых членов
END;
Delphi:
TYPE Derived = class (Base)
// определение новых членов
END;
В этих языках при наследовании используется не ключевое слово, а специальный синтаксис - добавление в скобках имени базового класса. Эти языки поддерживают только один тип наследования, который в C++ называется публичным.
Ada: type Base is tagged record
// члены end;
Type Derived is new Base with record
// определение новых членов end;
// новые члены не определяются, используется для добавления новых методов к базовому классу
Type Derived is new Base with null record;
package P is
type Base is tagged private;
………………………………………..
Где-то в конце есть спецификация пакета:
private
type Base is tagged record
….............................................
end P;
Где будем наследовать Base?
Если в этом же пакете, то делаем это так:
type Derived is new Base with private
..............................................................
Если это определение в том же модуле, то структура этого Derived должна быть описана в приватной части пакета.
Но если оба типа описываются в одном модуле, и у типа Base есть приватные члены, даже тогда относительно derived у него нет ничего приватного.
Защищенных членов в Ада и Оберон нет, таким образом, в этих языках всего два вида доступа:
-
публичный
-
приватный – его по большому счету тоже нет, так как в Ада есть дочений пакет.
package P.P1
Это означает, что фактически определяемое в нем как бы приписывается в конец приватной части в конце пакета.
Замечания:
1.В Java, C#, Delphi каждый класс происходит по крайней мере от некоторого базового класса по умолчанию. Этот класс обладает некоторыми основными способностями, доступными всем классам. Этот подход является общим ещё и потому, что так первоначально делалось в Smalltalk. Также любой класс может стать первым в иерархии классов в таких языках, как Оберон, Ада – 95.
2.Единственный язык, поддерживающий множественное наследование из языков, проходимых в курсе ООП – язык С++.
3. Единственный язык, поддерживающий модификацию прав доступа свойств базового класса в производном – язык С++.
Наследование и области видимости имен. Замещение, перегрузка и
скрытие имен при наследовании. Наследование и инкапсуляция. Управление
видимостью и доступом при наследовании.
class Base {
void f();
} ;
class Derived: public Base {
int f;
};
1)перегрузке(overloading) (в одной области действия)
2)скрытии(hiding)
3)переопределении(overriding) (динамическое связывание - рассмотрим чуть – чуть позднее)
Перегрузка функций(! Именно функций, так как не существует перегрузки свойств)
Понятие «перегрузка» означает, что одному имени в одной области видимости может соответствовать несколько определений. В современных языках программирования перегружаться могут только имена подпрограмм, но не типов, переменных, модулей.
Отличие перегрузки от замещения состоит во-первых, в том, что перегрузка обрабатывается статически (на этапе трансляции), в во-вторых, при замещении речь идет о разных областях видимости: базовый класс с объявлением виртуального метода (объемлющая область видимости) и производный класс с замещающим методом (вложенная область видимости).
Скрытие: скрытие происходит при наследовании, в унаследованном классе, если в производном классе есть такое же имя как в базовом.
Для того, чтобы ращличать две этих N, используются ключевые слова super, base, inherited:
super.N;
base.N;
inherited.N;
(Эти слова очень удобны, они позволяют держать в глове имя базового класса)
Переопределение: в переопределении главная роль уделяется виртуальным функциям, собственно в переопределении и заключен весь механизм работы виртуальных функций.
Запрещение наследования для классов и методов.
В С++ нет никаких ограничений с точки зрения наследования, то есть нет никаких языковых методов запретить наследования данного класса.
В Java можно запретить наследование с помощью ключевого слова final. Если это слово стоит перед именем метода, то этот метод не может переопределяться в производных классах. Если же оно стоит перед определением класса, то класс нельзя наследовать.
В C# такую роль играет sealed (там sealed имеет смысл ставить только около виртуальных методов). Sealed может стоять или перед определением, или перед замещением виртуального метода.
Любой сатический класс в C#3.0 запечатан.
Наследование и специальные функции. Понятие о множественном
наследовании.
Как было сказано выше из всех проходимых нами языков, множественное наследование реализовано только в С++, поэтому примеры ниже будут написаны на С++
синтаксис.
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 { ... };
Например, мы напишем: C.c; c.n = 0; Возникает неоднозначность: какую c нам вызвать, ту которая пришла к нам через A, или же ту, которая наследовалась через B. Здесь мы можем уточнить: c.A::n = 5; или c.B::n = 7;. Перед оператором разрешения контекста мы указываем точку, от которой начинается поиск переменной.
Замечание: в других языках тоже существует оператор уточнения (x::N ~ super.N ~ base.N ~ inherited.N)
10. Динамический полиморфизм
Статическое и динамическое связывание методов. Динамический тип
данных и динамическое связывание. Замещение функций и динамическое
связывание. Особенности динамического связывания в современных ЯП.
Виртуальность метода означает динамическое связывание метода при вызове метода через ссылку на объект (базового) класса. Будет вызван метод для объекта, на который в настоящее время указывает ссылка. Этот объект может относиться не к базовому, а к производному классу. если в производном классе метод замещен, то будет вызван не метод из базового класса (как в случае невиртуальных методов), а его заместитель.
Механизм виртуальных функций.
• Если вызываем метод через объект (h.print()), то виртуальность не работает, статическое определение по типу объекта, от которого его вызываем.
• При явном указании класса виртуальность не работает, даже если функция вызвана через указатель, то есть pp->Person::print(); – статическое определение.
С#, Delphi
Виртуальность метода обрывается, если мы не указываем virtual в очередном переопределении.
Ключевое слово override означает, что метод, в объявлении которого оно появляется, является заместителем виртуального метода из базового класса.
ADA 1995
Если есть параметр tегированного типа, для вызова есть специальные типы:
CWT – class wide types – классовый тип
Классовый тип – потенциально бесокнечное множество объектов, включающее все объекты класса Т и все производные объекта.
type T is tagged record …… end
T – класс, Т’ – классовый тип
type A is array (index range <>) of T;
X:A; //-ошибка!
X: A (range L..R); //нормально
X:T’
Тprocedure P (X: T);
T1procedure P (X: T1);
Представим, что существует некоторая глобальная процедура
procedure CALL(A : T); // P(A); -- P(X:T)
procedure CALLV (A : T’class) //P(A);
Тогда:
X: T;
Y:T1;
CALL(X); // - P(T)
CALL(Y); // - P(T)
CALLV(X); // - P(T)
CALLV(Y); // - P(T1)
Если речь идет о вызове классовго типа, то он может быть только динамический.
Оберон -2 отличается от Оберон тем, что в нем есть процедуры и динамическое приведение к типу – по определению аналог виртуальных методов.
Пример
TYPE T RECORD
……………………..
END;
TYPE T1 RECORD(T)
……………………..
END;
PROCEDURE(VAR X: T) P; //виртуаьная функция, Х передается как ссылка
Перекрытия нет, а замещение есть:
PROCEDURE(VAR X: T1) P; //динамическая(виртуальная) функция
VAR X: T;
Y: T1;
X.P; // -------------P(T)
Y.P; // --------------P(T1)
Вызывать таким образом можно лишь процедры, динамически привязанные к типу.
PROCEDURE CALL (VAR A: T); //обычная функция
Если имя функции написано после скобочек – функция виртуальная, если перед ним – то самая обычная.
Достоинства и недостатки динамического связывания. Снятие
динамического связывания. Механизм реализации динамического
связывания на примере языка Си++. Таблица виртуальных методов.
Понятие о мультиметодах.
Вообще говоря, Ада наиболее близко подошла к концепции МУЛЬТИМЕТОДА (метода, связанного по нескольким параметрам). Тем не менее, из соображений эффективности он в ней не реализован.
Мультиметод – это метод, который вызывается в зависимости от динамического типа двух своих ссылок.
CALL_W(X:T’ class, Y: W’ class);
P(X, Y);
Пример использования мультиметодов можно легко привести из компьютерной графики: пересечение объектов – вызываем ту или иную функцию в зависимости от способов пресечения.
Мультиметоды есть, например, в языке CLOS(Common Lisp With Object Systems) – достаточно известный язык в довольно узких кругах.
11. Абстрактные классы и интерфейсы
Понятие абстрактного класса (АК). Необходимость понятия АК при
проектировании иерархий классов. Воплощение концепции АК в
современных ЯП.
Абстрактные классы и интерфейсы. Интерфейс как языковая
конструкция. Связь интерфейсов и других языковых конструкций
(итераторов, сохраняемых объектов и т.д.). Интерфейсы и иерархии классов.
Сами по себе иерархии классов бесполезны, если в них нету динамически связанных методов.
• Если существуют признаки, общие для всех объектов в класса иерархии, то эти признаки целесообразно поместить в базовый класс
• У каждого объекта класса имеется состояние (текущие значения параметров) и поведение (методы класса)
• Некоторая функциональность (особенности поведения), общая для всех классов в иерархии, может быть реализована только при дальнейшей детализации в производных классах.
=> приходим к понятию абстрактного базового класса
В языках Delphi, Оберон-2, TP 5.5, C++, Java, C# имеется языковая поддержка абстрактных классов.
Пример:
Figure – абстрактная фигура
Общие данные – (x,y) – координаты фигуры
Общие методы – Draw(), Move() – не могут быть реализованы для абстрактной фигуры
Что будет если просто не определить витуальную функцию в базовом классе:
Полиморфный класс – класс, в котором есть виртуальные функции (и. следовательно, таблица виртуальных функций)
class X
{
public:
virtual void f(); //Объявлена, но не определена
void g();//Объявлена, но не определена
}
class Y: public X
{
public
virtual void f() {…;}//Замещена
}
….