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

В файле student2.H

Class student {

Public: //год обучения: новичок, второкурсник,

//младший, старший, аспирант

enum year { fresh, soph, junior, senior, grad};

//имя, номер, средний балл, год

void print () const;

protected:

int student_id; //номер студента

double gpa; //средний балл

year y; //год обучения

char name [30]; //имя

};

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

В файле student2.H

Class grad_student : public student (

рublic: //вариант финансовой поддержки:

//за преподавание, за исследования, стипендия, иное

enum support { ta, ra, fellowship, other };

grad_student (char* nm,int id, double g,

year x, support t, char* d, char* th);

//t – вариант финансовой поддержки,

//d – кафедра, th – тема диссертации

void print () const;

protected:

support s; //вариант финансовой поддержки

char dept [10]; //кафедра

char thesis [80]; //тема диссертации

};

В этом примере grad_student – производный класс, а student – базовый. Использование в заголовке производного класса ключевого слова рublic, следующего за двоеточием, означает, что защищенные и открытые (protected и public) члены класса должны наследоваться как защищенные и открытые члены grad_student. Закрытые члены базового класса недоступны производному классу. Открытое наследование означает также, что производный класс grad_student является подтипом student. То есть аспирант является студентом, но студент не обязательно должен быть аспирантом. Такое отношение подтипов называется отношением ISA1. Иногда его также называют интерфейсным наследованием (interface inheritance).

Производный класс является модификацией базового класса; он наследует защищенные и открытые члены базового класса. Не могут наследоваться только конструкторы, деструктор базового класса и любые функции-члены operator=(). Так в примере с классом grad_student наследуются следующие члены класса student: student_id, gpa, name, y и print (). Часто в производный класс добавляются новые члены в дополнение к членам базового класса. Это происходит и в случае с grad_student, который содержит три новых члена данных и переопределенную функцию-член print(). Эта функция замещается (override). Определение функций student :: print () и

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

Преимущества использования производных классов

▪ Код используется повторно. Тип grad_student использует существующий, проверенный код из student.

▪ Иерархия отражает взаимоотношения, свойственные проблемной области. Когда мы говорим о студентах, выделение аспирантов в отдельную группу заимствуется из реального мира и определяется тем, как аспиранты понимается в этом мире.

▪ Различные полимерные механизмы позволят клиентскому коду рассматривать в качестве подтипа student, что упростит клиентский код, сохраняя при этом преимущества разграничения подтипов.

Преобразование типов и видимость

Открытый производный класс является подтипом своего базового класса. Во многих случаях переменная производного класса может рассматриваться как переменная типа базового класса. Указатель, тип которого – «указатель на базовый класс», может указывать на объекты, имеющие тип производного класса.

Рассмотрим наш пример с классами student и grad_student. Сначала исследуем конструкторы базового и производного классов.

В файле student2.h

student::student (char* nm, int id, double g, year x)

: student_id (id), gpa(g), y(x)

{

stropy (name, nm);

}

Конструктор базового класса выполняет несколько простых инициализаций. Затем он вызывает stropy ()для копирования имени студента.

grad_student::grad_student (сhar* nm, int id, double g,

year x, support t, сhar* th)

: student(nm,id,g,x), s(t)

{

stropy(dept, d);

stropy(thesis, th);

Заметьте, что здесь конструктор student вызывается как часть списка инициализаторов. Это вполне естественно и логично – для завершения создания объекта сначала надо создать объект базового класса.

Тип grad_student является открытым производным типом, базовый класс которого – student. В классе student члены student_id и gpa являются защищенными. Это делает их видимыми для производных классов, но для всех остальных они ведут себя как закрытые.

Ссылка на производный класс может быть неявно преобразована в ссылку на открытый базовый класс. Например:

grad_student gs («Моррис Пол», 200, 3.2564, grad, ta,

«Фармокология», «Продажа лекарств»);

student& rs = gs;

В данном случае переменная rs является ссылкой на student. Базовым классом grad_student является student. Поэтому такое преобразование ссылки справедливо.

Функции-члены print()реализованы следующим образом:

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