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

Глава 2. Ориентированный на объект дизайн

Специальные привилегии доступа для производных классов могут быть обеспечены, объявив, что мадам - bers «защищена». Защищенный участник «общественный» ко всем классам, полученным от этого, но «частный» ко всем другим функциям. С синтаксической точки зрения защищенное ключевое слово ведет себя таким же образом как ключевое слово, частное и общественное. В примере класса выше, имел, мы объявили, что имя было защищено, а не частные, вышеупомянутая функция printName будет хорошо работать.

Хотя C ++ не делает требований к заказу, в котором появляются различные секунды - tions класса, есть два распространенных способа сделать его. Первое должно объявить общественных участников первыми и членами парламента, не занимающими официального поста в последний раз. Это подчеркивает монетные дворы ele-, которые важны для пользователя класса. Другой путь состоит в том, чтобы представить членов парламента, не занимающих официального поста сначала и общественных участников в последний раз. Это имеет тенденцию быть легче читать для im-plementor. Конечно, ясность - более важное соображение, чем приверженность любому стандарту.

Иллюстрирование защиты класса

Рассмотрите, например, три класса: Основа базового класса, Полученный производный класс, и

несвязанный Не связанный класс. Базовый класс определяет трех участников целого числа, один из каждого типа доступа.

Основа класса

частный: интервал priv;

защищенный: международный протестант; общественность: интервал publ;

;

Полученный класс: общественная Основа

пустота someMemberFunction ()

суд <<priv;

суд <<протестант; единое время co <<p ubl;

//ОШИБКА: член парламента, не занимающий официального поста//хорошо//хорошо

;

класс, Не связанный

Основа X;

пустота anotherMemberFunction ()

суд <<X.priv;

суд <<X.prot; суд <<X.publ;

//ОШИБКА: член парламента, не занимающий официального поста//ОШИБКА: защищенный участник//хорошо

;

Проектируя класс, мы должны тщательно обдумать доступ privi-leges, мы даем каждую членскую переменную или функцию. Членские переменные почти

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

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

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

Конструкторы и печи для сжигания отходов производства

Мы видели в Разделе 1.5.2, это, когда объект класса создан, конструктор класса

назван. Когда производный класс построен, это - обязанность конструктора этого класса заботиться, которым соответствующего конструктора называют для его базового класса. Иерархии классов в C ++ построены вверх дном: базовый класс сначала, тогда его мадам - bers, тогда сам производный класс. Поэтому конструктора для базового класса нужно назвать в списке инициализатора (см. Раздел 1.5.2) производного класса. Пример ниже показывает, как конструкторы могли бы быть осуществлены для Человека и Студенческих классов.

Человек:: Человек (константа string& nm, константа string& id)

: имя (nm), //инициализируют имя

idNum (id) //инициализируют идентификационный номер

Студент:: Студент (константа string& nm, константа string& id,

константа string& майор, международный год)

: Человек (nm, id), //инициализируют участников Человека, крупных (майор), //инициализируют главный

gradYear (год) //инициализируют год церемонии вручения дипломов

Только Человек (nm, id) требование должно быть в списке инициализатора. Другие инициализации могли быть помещены в тело функции конструктора ({...}), но помещение класса initializa-

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

новый студенческий объект.

Студент* s = новый Студент («Гимн», «34-927», «Физика», 2014);

Обратите внимание на то, что конструктор для Студенческого класса сначала делает вызов функции к За - сын («Гимн», «34-927»), чтобы инициализировать базовый класс Человека, и затем это инициализирует майора к «Физике» и год к 2014.

Классы разрушены в обратном порядке от их строительства с производными классами, разрушенными перед базовыми классами. Например, предположите, что мы объявили de - structors для этих двух классов. (Обратите внимание на то, что печи для сжигания отходов производства не действительно необходимы в этом случае, потому что никакой класс не ассигнует хранение или другие ресурсы.)

Человек:: ˜Person () //печь для сжигания отходов производства Человека

Студент:: ˜Student () //Студенческая печь для сжигания отходов производства

76

Глава 2. Ориентированный на объект Дизайн, Если бы мы должны были разрушить наш студенческий объект, Студенческая печь для сжигания отходов производства, назвали бы первым, сопровождаемым печью для сжигания отходов производства Человека. В отличие от конструкторов, Студенческой печи для сжигания отходов производства не нужно к (и не позволен), называют печь для сжигания отходов производства Человека. Это происходит автоматически.

удалите s; //называет ˜Student () тогда ˜Person ()

Статическое закрепление

Когда класс получен из базового класса, как со Студентом и Человеком, полученным

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

Человек* стр [100]; //множество 100 стр указателей Человека [0] = новый Человек (...); //добавляют Человека (опущенные детали) стр [1] = новый Студент (...); //добавляют Студента (опущенные детали)

Так как getName характерен для обоих классов, он может быть призван на любой элементы множества. Более интересная проблема возникает, если мы пытаемся призвать печать. Начиная с стр [1] держит адрес Студенческого объекта, мы могли бы думать, что функция Сту - вдавливает:: печать назвали бы. Удивительно, Человек функции:: печать называют в обоих случаях, несмотря на очевидную разницу в двух объектах. Кроме того, стр [мне] даже не разрешают получить доступ к Студенческим членским функциям.

суд <<стр [1]-> getName () <<'\n';

//

хорошо

стр [0]-> печать ();

//

Человек требований:: печать ()

стр [1]-> печать ();

//

также Человек требований:: печать () (!)

стр [1]-> changeMajor («английский язык»);

//

ОШИБКА!

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

Динамическое закрепление и виртуальные функции

Как мы видели выше, C ++ использует статическое закрепление по умолчанию, чтобы определить который участник

функционируйте, чтобы призвать к производному классу. Альтернативно, в динамическом закреплении, содержание объекта определяет, какая членская функция вызвана. Чтобы определить, что членская функция должна использовать динамическое закрепление, «виртуальное» ключевое слово добавлено к декларации func-tion. Давайте пересмотрим нашу Личность и Студента, но на сей раз мы будем