Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции / LECS17.DOC
Скачиваний:
48
Добавлен:
16.04.2013
Размер:
151.55 Кб
Скачать

В файле student2.H

void student::print() const

{

count << name << "," << student_id

<< " , " << y<< " , " << gpa << end1;

}

void grad_ student::print() const

{

student:: print(); //печатается информация базового класса

сout << dept << " , " << s << ‘\n’

<< thesis << end1;

}

При вызове функции student::print() из grad_student::print() обязательно должен использоваться индефикатор, разрешающий область видимости. Именно так: student::print(). Иначе из-за рекурсивных вызовов grad_student::print()возникнет бесконечный цикл. Чтобы увидеть, какая из двух версий этих функций будет вызвана и продемонстрировать некоторые отношения преобразований между базовыми и открытыми производным классом, напишем простой текст:

В файле student2.Cpp

//Проверим правила преобразователей указателей

#include "student2.h" //включаем наши объявления

int main()

{

student s («Мей Пол», 100,3.425, student::fresh) , *ps=&s;

grad_student gs («Моррис Пол»», 200,3,2564,

student::grad, grad_student::ta, «Фармокология»,

«Продажа лекарств»), *pgs;

ps -> print(); // student::print

ps = pgs = &gs;

pgs -> print(); //grad_student::print

ps -> print(); //student::print

}

Эта программа объявляет переменные класса и указатели на них. Правило преобразования состоит в том, что указатель на производный класс может быть неявно преобразован к указателю на его базовый класс. В нашем примере переменная-указатель ps может указывать на объекты обоих классов, а переменная-указатель pgs – только на объекты типа grad_student. Мы хотим выяснить, как различные присваивания указателей влияют на то, какая версия print() будет вызвана.

В первом случае инструкция

ps -> print();

вызовет student::print(). Переменная ps указывает на переменную s типа student. В инструкции множественного присваивания

ps = pgs = &gs;

оба указателя направлены на объект типа grad_student. Присваивание приводит к неявному преобразователю. Инструкция

pgs -> print();

вызывает grad_student::print(). Переменная pgs имеет тип «указатель на grad_student», и при вызове с объектом этого типа выбирается функция-член из этого класса. Второй раз инструкция

ps -> print();

вызывает student::print(). Тот факт, что этот указатель теперь указывает на переменную gs типа grad_student к делу не относится: в разделе 1.4, «Виртуальные функции», объясним, как использовать виртуальные функции члены для того, чтобы выбор называемой функции определялся на этапе выполнения, в зависимости от того, на что направлен указатель.

Повторное использование кода: класс двоичного дерева

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

Часто повторное использование кода – это все, что мы хотим от наследования. Покажем, как закрытое наследование используется при создании обобщенного контейнерного класса – двоичного дерева. Эта древесная структура была также использована в качестве шаблонного класса. Шаблоны и наследование – это способы повторного использования кода, обладающими разными преимуществами. Обычно шаблоны легче проектировать; кроме того, исполняемый код, сгенерированный на их основе, работает быстрее, но занимает больше места.

Класс будет хранить члены данных .void*. Идея состоит в закрытом наследовании от этого класса, чтобы, так сказать, «разобщить» указатели void*..

Соседние файлы в папке Лекции