Использование спецификатора protected для наследования базового класса



 

Спецификатор protected можно использовать не только для придания членам класса статуса "защищенности", но и для наследования базового класса. Если базовый класс наследуется как защищенный, все его открытые и закрытые члены становятся защищенными членами производного класса. Рассмотрим пример.

 

 

Как отмечено в комментариях к этой программе, члены (класса base) k , j , seti() и geti() становятся protected ‑членами класса derived . Это означает, что к ним нельзя получить доступ из кода, "прописанного" вне класса derived . Поэтому ссылки на эти члены в функции main() (через объект ob ) неправомочны.

 

Об использовании спецификаторов public, protected и private

 

Поскольку права доступа, определяемые спецификаторами public , protected и private , принципиальны для программирования на C++, имеет смысл обобщить все, что мы уже знаем об этих ключевых словах.

При объявлении члена класса открытым (с использованием ключевого слова public ) к нему можно получить доступ из любой другой части программы. Если член класса объявляется закрытым (с помощью спецификатора private ), к нему могут получать доступ только члены того же класса. Более того, к закрытым членам базового класса не имеют доступа даже производные классы. Если же член класса объявляется защищенным (protected ‑членом), к нему могут получать доступ только члены того же или производных классов. Таким образом, спецификатор protected позволяет наследовать члены, но оставляет их закрытыми в рамках иерархии классов.

 

Если базовый класс наследуется с использованием ключевого слова public , его public ‑члены становятся public ‑членами производного класса, а его protected ‑члены – protected ‑членами производного класса.

 

Если базовый класс наследуется с использованием спецификатора protected , его public ‑ и protected ‑члены становятся protected ‑членами производного класса.

 

Если базовый класс наследуется с использованием ключевого слова private , его public ‑ и protected ‑члены становятся private ‑членами производного класса.

 

Во всех случаях private ‑члены базового класса остаются закрытыми в рамках этого класса и не наследуются.

По мере увеличения вашего опыта в программировании на C++ применение спецификаторов public , protected и private не будет доставлять вам хлопот. А пока, если вы еще не уверены в правильности использования того или иного спецификатора доступа, напишите простую экспериментальную программу и проанализируйте полученные результаты.

 

Наследование нескольких базовых классов

 

Производный класс может наследовать два или больше базовых классов. Например, в этой короткой программе класс derived наследует оба класса base1 и base2 .

 

 

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

 

Конструкторы, деструкторы и наследование

 

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

 

Когда выполняются конструкторы и деструкторы

 

Базовый и/или производный класс может содержать конструктор и/или деструктор. Важно понимать порядок, в котором выполняются эти функции при создании объекта производного класса и его (объекта) разрушении.

Рассмотрим короткую программу.

 

 

Как отмечено в комментариях для функции main(), эта программа лишь создает и тут же разрушает объект ob , который имеет тип derived . При выполнении программа отображает такие результаты.

 

 

Судя по результатам, сначала выполняется конструктор класса base , а за ним – конструктор класса derived . Затем (по причине немедленного разрушения объекта ob в этой программе) вызывается деструктор класса derived , а за ним – деструктор класса base .

Конструкторы вызываются в порядке происхождения классов, а деструкторы – в обратном порядке.

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

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

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

При расширенной иерархии классов (т.е. в ситуации, когда производный класс становится базовым классом для еще одного производного) применяется следующее общее правило: конструкторы вызываются в порядке происхождения классов, а деструкторы – в обратном порядке. Например, при выполнении этой программы

 

 

отображаются такие результаты:

 

 

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

 

 

генерируются такие результаты:

 

 

Как видите, конструкторы вызываются в порядке происхождения их классов, слева направо, в порядке их задания в списке наследования для класса derived . Деструкторы вызываются в обратном порядке, справа налево. Это означает, что если бы класс base2 стоял перед классом base1 в списке класса derived , т.е. в соответствии со следующей инструкцией:

 

 

то результаты выполнения предыдущей программы были бы такими:

 


Дата добавления: 2018-09-22; просмотров: 502; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!