Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP_otvety_k_ekzamenu.doc
Скачиваний:
55
Добавлен:
13.04.2015
Размер:
786.94 Кб
Скачать

27. Конструкторы и деструкторы при наследовании. Моменты и порядок вызовов конструкторов. Передача аргументов конструкторам базового класса.

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

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

Руководствуясь теми же соображениями, при уничтожении объекта производного сначала выполняется тело его непосредственного деструктора, затем вызывается деструктор дочернего объекта, и, наконец, деструктор базового класса. Данные базового класса, на которые может ссылаться конкретный производный класс, должны существовать в корректном состоянии все время его жизни. Соответственно, вызывать деструктор базового класса безопасно только после завершения деструктора производного класса и его дочерних объектов.

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

Определять конструктор в производном классе не обязательно только в том случае, если базовый класс имеет конструктор по умолчанию (в таком случае, компилятор просто будет вызывать этот конструктор базового класса).

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

28. Спецификатор доступа protected. Защищенные конструкторы и методы.

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

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

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

Класс Account реализует общие свойства всех учетных записей, включая проверку пароля. Пароль непосредственно не хранится, вместо него используется хэш-код. При авторизации производные классы должны передать в защищенный метод authorize введенный пароль, и если хэш-код от пароля совпадает с образцом, авторизация выполняется успешно.

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]