Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Data Structures and Algorithms in C++ 2e (На ру...docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.37 Mб
Скачать

2.2. Наследование и полиморфизм 87

Проблема состоит в том, что у Человека базового класса нет функции changeMajor.

Заметьте, что это отличается от случая печати функции, потому что функция печати была обеспечена в обоих классах. Тем не менее, мы «знаем», что стр [1] пункты к объекту Студента класса, таким образом, эта операция должна быть законной.

Чтобы получить доступ к функции changeMajor, мы должны бросить стр [1] указатель от Человека типа*, чтобы напечатать Student*. Поскольку содержание переменной динамичное, мы должны использовать C ++ система во время выполнения, чтобы определить, законен ли этот бросок, который является тем, что делает динамический бросок. Синтаксис динамического броска показывают ниже.

динамический бросок <желаемый тип> (выражение)

Динамический кастинг может только быть применен к полиморфным объектам, то есть, объекты, которые прибывают из класса по крайней мере с одной виртуальной функцией. Ниже мы показываем, как использовать динамический кастинг, чтобы изменить майора стр [1].

Студент* SP = динамический бросок <Студент*> (стр [1]);//стр броска [1] Студенту*

SP-> changeMajor («Химия»); //теперь changeMajor законен

Динамический кастинг чаще всего применен для кастинга указателей в пределах иерархии классов. Если незаконный бросок указателя предпринят, то результат - пустой указатель. Например, мы получили бы ПУСТОЙ указатель от попытки бросить стр [0] как выше, так как это указывает на объект Человека.

Чтобы иллюстрировать использование динамического броска, мы получаем доступ ко всем элементам множества стр

и для объектов (фактического) Студента типа измените майора на «Нерешенный»

для (интервал i = 0; я <100; я ++)

Студент *SP = динамический бросок <Студент*> (стр [я]);

если (SP! = ПУСТОЙ УКАЗАТЕЛЬ) //авария t s ucceeded?

SP-> changeMajor («Нерешенный»); //главное изменение

Кастинг, который мы обсудили здесь, возможно, также был сделан, используя tradi-tional бросок C-стиля, или посредством статического броска (вспомните Раздел 1.2.1). К сожалению, никакая проверка на ошибки не была бы выполнена в этом случае. Попытка бросить указатель объекта Человека на Студенческий указатель преуспела бы «тихо», но у любой попытки использовать такой указатель будут катастрофические последствия.

2.2.5 Интерфейсы и абстрактные классы

Для двух объектов взаимодействовать, они должны «знать» об участнике друг друга func-

tions. Чтобы провести в жизнь это «знание», ориентированная на объект парадигма дизайна просит, чтобы классы определили интерфейс прикладного программирования (API), или просто взаимодействовали, что их объекты представляют другим объектам. В основанном на ADT подходе (см. Секунду - tion 2.1.2) к структурам данных, сопровождаемым в этой книге, интерфейс, определяющий ADT

88

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

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

C ++ не обеспечивает прямой механизм для определения интерфейсов. Nonethe-меньше, всюду по этой книге, мы часто обеспечиваем неофициальные интерфейсы, даже при том, что они не юридический C ++ структуры. Например, структура данных стека (см. Главу 5) является контейнером, который поддерживает различные операции, такие как вставка (или подталкивание) элемент на вершину стека, удаление (или сование) элемент от вершины стека и тестирование, пуст ли стек. Ниже мы обеспечиваем пример минимального интерфейса для стека целых чисел.

Стек класса //неофициальный интерфейс - не класс

общественность:

bool isEmpty () константа; //действительно ли стек пуст? недействительный толчок (интервал x); //выдвигают x на популярность интервала стека (); //суют результат возвращения и стек

;

Абстрактные классы

Вышеупомянутый неофициальный интерфейс не действительная конструкция в C ++; это - просто documen-

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

Абстрактный класс в C ++ является классом, который используется только в качестве базового класса для inheri-tance; это не может использоваться, чтобы создать случаи непосредственно. Сначала идея создать класс, который не может иллюстрироваться примерами, кажется, не имеет смысла, но это часто очень важно. Например, предположите, что мы хотим определить ряд геометрических классов формы, скажем, Круг, Прямоугольник и Треугольник. Естественно получить эти связанные классы из единственного универсального базового класса, скажем, Форма. Каждый из производных классов сделает, чтобы виртуальный участник функционировал, тянут, который тянет связанный объект. Правила наследования требуют, чтобы мы определили такую функцию для базового класса, но неясно, что такая функция означает для универсальной формы.

Один способ обращаться с этим состоял бы в том, чтобы определить Форму:: потяните с пустой функцией

тело (), который был бы довольно неестественным решением. Что действительно желаемо

вот некоторый способ сообщить компилятору, что Форма класса абстрактна; это не

возможный создать объекты Формы типа, только ее подклассы. В C ++, мы определяем класс, как являющийся абстрактным, определяя, что один или несколько членов его функций абстрактны, или чистые виртуальный. Функция объявлена чистой виртуальный, дав «=0» в