Основы программирования — второй семестр 08-09; Михалкович С.С.; VI часть — различия между версиями

Материал из Вики ИТ мехмата ЮФУ
Перейти к: навигация, поиск
(Наследование на примере Student - SeniorStudent)
(Наследование на примере Student - SeniorStudent)
Строка 205: Строка 205:
 
   private
 
   private
 
     fAdvisor: Teacher;
 
     fAdvisor: Teacher;
     fEduModel: DegreeType;
+
     fDegree: DegreeType;
 
     fCourseWorkTheme: string;
 
     fCourseWorkTheme: string;
 
      
 
      
 
     procedure SetAdvisor(Advisor: Teacher);
 
     procedure SetAdvisor(Advisor: Teacher);
     procedure SetDegree(degree: DegreeType);
+
     procedure SetDegree(Degree: DegreeType);
 
      
 
      
 
     /// Устанавливает тему курсовой работы, получая её от научного руководителя
 
     /// Устанавливает тему курсовой работы, получая её от научного руководителя
Строка 232: Строка 232:
 
</source>
 
</source>
  
Как реализовать сеттеры, <tt>GetCourseWorkTheme</tt> и NextCourse мы знаем:
+
Как реализовать сеттеры, <tt>GetCourseWorkTheme</tt> и <tt>NextCourse</tt> мы знаем:
 
<source lang="Delphi">
 
<source lang="Delphi">
 
procedure SeniorStudent.SetAdvisor(Advisor: Teacher);
 
procedure SeniorStudent.SetAdvisor(Advisor: Teacher);
Строка 239: Строка 239:
 
end;
 
end;
  
procedure SeniorStudent.SetEduModel(EduModel: EduModelType);
+
procedure SeniorStudent.SetDegree(Degree: DegreeType);
 
begin
 
begin
   fEduModel := EduModel;
+
   fDegree := Degree;
 
end;
 
end;
  
Строка 251: Строка 251:
 
procedure SeniorStudent.NextCourse;
 
procedure SeniorStudent.NextCourse;
 
begin
 
begin
   var maxCourse := MaxCourseByEduModel(EduModel);
+
   var maxCourse: integer;
 +
  case fDegree of
 +
    Bachelor: maxCourse:= 4;
 +
    Specialist: maxCourse:= 5;
 +
    Magister: maxCourse:= 6;
 +
  end;
 +
 
 
   if fCourse < maxCourse then
 
   if fCourse < maxCourse then
 
   begin
 
   begin
Строка 280: Строка 286:
 
<source lang="Delphi">
 
<source lang="Delphi">
 
constructor SeniorStudent.Create(Name: string; Age, Course, Group: integer;  
 
constructor SeniorStudent.Create(Name: string; Age, Course, Group: integer;  
   Advisor: Teacher; EduModel: EduModelType);
+
   Advisor: Teacher; Degree: DegreeType);
 
begin
 
begin
 
   inherited Create(Name, Age, Course, Group);
 
   inherited Create(Name, Age, Course, Group);
 
   fAdvisor := Advisor;
 
   fAdvisor := Advisor;
   fEduModel := EduModel;
+
   fDegree := Degree;
 
   GetCourseWorkTheme;
 
   GetCourseWorkTheme;
 
end;
 
end;
Строка 294: Строка 300:
 
   write('Преподаватель: ');   
 
   write('Преподаватель: ');   
 
   fAdvisor.Print;
 
   fAdvisor.Print;
   writeFormat('Тема курсовой работы: «{0}»  ', CourseWorkTheme);
+
   writeFormat('Тема курсовой работы: «{0}»  ', fCourseWorkTheme);
 
    
 
    
   writeFormat('Образовательная степень: {0}', StringEduModel(EduModel));
+
   write('Образовательная степень: ');
 +
  case fDegree of
 +
    Bachelor:  write('Бакалавр');
 +
    Specialist: write('Специалист');
 +
    Magister:  write('Магистр');
 +
  end;
 
end;
 
end;
  
Строка 306: Строка 317:
 
</source>
 
</source>
  
 
+
Заметим, что можно выделить две дополнительных функции для работы с академической степенью:
{{Hider
+
* <tt>function MaxCourseByDegree(degree: DegreeType): integer</tt>, <br />возвращающую максимальный курс, соответствующий образовательной степени degree
|title = Полный текст текущего модуля
+
* <tt>function StringDegree(degree: DegreeType): string</tt>, <br />возвращающую строковое представление академической степени («Бакалавр», «Специалист» или «Магистр»)
|content =
+
и использовать их в методах <tt>SeniorStudent.NextCourse</tt> и <tt>SeniorStudent.Print</tt>.
<source lang="Delphi">
 
unit University;
 
 
 
interface
 
uses System;
 
 
 
const 
 
  /// Минимальный допустимый возраст студента
 
  MIN_AGE = 1;
 
  /// Максимальный допустимый возраст студента
 
  MAX_AGE = 120;
 
 
 
  /// Минимальный возможный курс
 
  MIN_COURSE = 1;
 
 
 
// ============================================ Student =========================================== 
 
const
 
  /// Максимальный возможный курс
 
  MAX_COURSE = 4;
 
 
 
type
 
  /// Студент
 
  Student = class
 
  private
 
    /// Имя
 
    fName: string;
 
    /// Возраст
 
    fAge: integer;
 
    /// Курс
 
    fCourse: integer;
 
    /// Группа
 
    fGroup: integer;
 
   
 
    procedure SetName(Name: string);
 
    procedure SetAge(Age: integer);
 
    procedure SetCourse(Course: integer);
 
    procedure SetGroup(Group: integer);
 
   
 
    procedure IncAge;
 
   
 
  public
 
    /// Имя — только на чтение
 
    property Name: string read fName;
 
    /// Возраст — только на чтение
 
    property Age: integer read fAge;
 
    /// Курс — только на чтение
 
    property Course: integer read fCourse;
 
    /// Группа — только на чтение
 
    property Group: integer read fGroup;
 
   
 
    /// <summary>
 
    /// Создает нового студента
 
    /// </summary>
 
    /// <param name="Name">Имя (пустое недопустимо)</param>
 
    /// <param name="Age">Возраст (отрицательный или больший MAX_AGE недопустим)</param>
 
    /// <param name="Course">Курс (отрицательный или больший MAX_COURSE недопустим)</param>
 
    /// <param name="Group">Группа (отрицательная недопустима)</param>
 
    constructor Create(Name: string; Age, Course, Group: integer);
 
   
 
    /// Переводит студента на следующий курс, если он меньше MAX_COURSE
 
    procedure NextCourse;
 
   
 
    procedure Print;
 
    procedure Println;
 
  end;
 
 
 
// ========================================== EduModelType ======================================== 
 
type
 
  /// Образовательная степень (Бакалавр, Специалист, Магистр)
 
  EduModelType = (Bachelor, Specialist, Magister);
 
 
 
/// Возвращает максимальный курс, соответствующий образовательной степени eduModel
 
function MaxCourseByEduModel(eduModel: EduModelType): integer;
 
 
 
/// Возвращает строковое представление образовательной степени
 
function StringEduModel(eduModel: EduModelType): string;
 
 
 
// ============================================ Teacher ===========================================
 
type
 
  SeniorStudent = class; // предописание класса
 
 
 
  /// Преподаватель
 
  Teacher = class
 
  private
 
    /// Имя
 
    fName: string;
 
 
 
    procedure SetName(Name: string);
 
 
 
  public
 
    /// Имя — только на чтение
 
    property Name: string read fName;
 
   
 
    /// <summary>
 
    /// Создает нового преподавателя
 
    /// </summary>
 
    /// <param name="Name">Имя (пустое недопустимо)</param>
 
    constructor Create(Name: string);
 
   
 
    /// Возвращает тему курсовой работы для студента MyStudent
 
    function SayCourseWorkTheme(MyStudent: SeniorStudent): string;
 
   
 
    procedure Print;
 
    procedure Println;
 
  end;
 
 
 
// ========================================= SeniorStudent ======================================== 
 
  /// Студент старших курсов
 
  SeniorStudent = class (Student)
 
  private
 
    /// Научный руководитель
 
    fAdvisor: Teacher;
 
    /// Образовательная степень
 
    fEduModel: EduModelType;
 
    /// Тема курсовой работы
 
    fCourseWorkTheme: string; 
 
 
 
    procedure SetAdvisor(Advisor: Teacher);
 
    procedure SetEduModel(EduModel: EduModelType);
 
   
 
    /// Устанавливает тему курсовой работы, получая её от научного руководителя
 
    procedure GetCourseWorkTheme;
 
   
 
  public
 
    /// Научный руководитель — только на чтение
 
    property Advisor: Teacher read fAdvisor;
 
    /// Образовательная степень — только на чтение
 
    property EduModel: EduModelType read fEduModel;
 
    /// Тема курсовой работы — только на чтение
 
    property CourseWorkTheme: string read fCourseWorkTheme;
 
   
 
    /// <summary>
 
    /// Создает нового студента старших курсов
 
    /// </summary>
 
    /// <param name="Name">Имя (пустое недопустимо)</param>
 
    /// <param name="Age">Возраст (отрицательный или больший MAX_AGE недопустим)</param>
 
    /// <param name="Course">Курс (отрицательный или больший MAX_COURSE недопустим)</param>
 
    /// <param name="Group">Группа (отрицательная недопустима)</param>
 
    /// <param name="Advisor">Научный руководитель</param>
 
    /// <param name="EduModel">Образовательная степень (бакалавр, специалист, магистр)</param>
 
    constructor Create(Name: string; Age, Course, Group: integer;
 
      Advisor: Teacher; EduModel: EduModelType);
 
   
 
    procedure NextCourse;
 
   
 
    procedure Print;
 
    procedure Println;
 
  end;
 
 
 
implementation
 
 
 
// ============================================ Student ===========================================
 
 
 
procedure Student.SetName(Name: string);
 
begin
 
  if Name <> '' then
 
    fName := Name
 
  else
 
    raise new Exception(
 
    'Попытка присвоить студенту пустое имя!');
 
end;
 
 
 
procedure Student.SetAge(Age: integer);
 
begin
 
  if (Age >= MIN_AGE) and (Age <= MAX_AGE) then
 
    fAge := Age
 
  else
 
    raise new Exception(
 
    'Выход за границы диапазона допустимого возраста [' +
 
    MIN_AGE.ToString + '..' + MAX_AGE.ToString + ']!');
 
end;
 
 
 
procedure Student.SetCourse(Course: integer);
 
begin
 
  if (Course >= MIN_COURSE) and (Course <= MAX_COURSE) then
 
    fCourse := Course
 
  else
 
    raise new Exception(
 
    'Выход за границы диапазона допустимых курсов [' +
 
    MIN_COURSE.ToString + '..' + MAX_COURSE.ToString + ']!');
 
end;
 
 
 
procedure Student.SetGroup(Group: integer);
 
begin
 
  if (Group > 0) then
 
    fGroup := Group
 
  else
 
    raise new Exception(
 
    'Попытка присвоить гурппе отрицательный номер!');
 
end;
 
 
 
procedure Student.IncAge;
 
begin
 
  if fAge < MAX_AGE then
 
    fAge += 1
 
  else
 
    raise new Exception(
 
    'Выход за границы диапазона допустимого возраста [' +
 
    MIN_AGE.ToString + '..' + MAX_AGE.ToString + ']!');
 
end;
 
 
 
constructor Student.Create(Name: string; Age, Course, Group: integer);
 
begin
 
  SetName(Name);
 
  SetAge(Age);
 
  SetCourse(Course);
 
  SetGroup(Group);
 
end;
 
 
 
procedure Student.NextCourse;
 
begin
 
  if fCourse < MAX_COURSE then
 
  begin
 
    fCourse += 1;
 
    IncAge;
 
  end
 
  else
 
    raise new Exception(
 
    'Выход за границы диапазона допустимых курсов [' +
 
    MIN_COURSE.ToString + '..' + MAX_COURSE.ToString + ']!');
 
end;
 
 
 
procedure Student.Print;
 
begin
 
  WriteFormat(
 
  'Имя: {0}  Возраст: {1}  Курс: {2}  Группа: {3}  ',
 
  fName, fAge, fCourse, fGroup);
 
end;
 
 
 
procedure Student.Println;
 
begin
 
  Print;
 
  writeln();
 
end;
 
 
 
// ============================================ Teacher ===========================================
 
 
 
procedure Teacher.SetName(Name: string);
 
begin
 
  if Name <> '' then
 
    fName := Name
 
  else
 
    raise new Exception(
 
    'Попытка присвоить преподавателю пустое имя!');
 
end;
 
 
 
constructor Teacher.Create(Name: string);
 
begin
 
  SetName(Name);
 
end;
 
 
 
function Teacher.SayCourseWorkTheme(MyStudent: SeniorStudent): string;
 
begin
 
  result := 'Тема курсовой работы';
 
end;
 
 
 
procedure Teacher.Print;
 
begin
 
  WriteFormat(
 
  'Имя: {0}  ',
 
  fName);
 
end;
 
 
 
procedure Teacher.Println;
 
begin
 
  Print;
 
  writeln();
 
end;
 
 
 
// ========================================== EduModelType ======================================== 
 
 
 
function MaxCourseByEduModel(eduModel: EduModelType): integer;
 
begin
 
  case eduModel of
 
    Bachelor: result := 4;
 
    Specialist: result := 5;
 
    Magister: result := 6;
 
  end;
 
end;
 
 
 
function StringEduModel(eduModel: EduModelType): string;
 
begin
 
  case eduModel of
 
    Bachelor: result := 'Бакалавр';
 
    Specialist: result := 'Специалист';
 
    Magister: result := 'Магистр';
 
  end;
 
end;
 
 
 
 
 
// ========================================= SeniorStudent ======================================== 
 
 
 
procedure SeniorStudent.SetAdvisor(Advisor: Teacher);
 
begin
 
  fAdvisor := Advisor;
 
end;
 
 
 
procedure SeniorStudent.SetEduModel(EduModel: EduModelType);
 
begin
 
  fEduModel := EduModel;
 
end;
 
 
 
procedure SeniorStudent.GetCourseWorkTheme;
 
begin
 
  fCourseWorkTheme := fAdvisor.SayCourseWorkTheme(self);
 
end;
 
 
 
constructor SeniorStudent.Create(Name: string; Age, Course, Group: integer;
 
  Advisor: Teacher; EduModel: EduModelType);
 
begin
 
  inherited Create(Name, Age, Course, Group);
 
  fAdvisor := Advisor;
 
  fEduModel := EduModel;
 
  GetCourseWorkTheme;
 
end;
 
 
 
procedure SeniorStudent.NextCourse;
 
begin
 
  var maxCourse := MaxCourseByEduModel(EduModel);
 
  if fCourse < maxCourse then
 
  begin
 
    fCourse += 1;
 
    IncAge;
 
  end
 
  else
 
    raise new Exception(
 
    'Выход за границы диапазона допустимых курсов [' +
 
    MIN_COURSE.ToString + '..' + maxCourse.ToString + ']!');
 
end;
 
 
 
procedure SeniorStudent.Print;
 
begin
 
  inherited Print;
 
 
 
  write('Преподаватель: '); 
 
  fAdvisor.Print;
 
  writeFormat('Тема курсовой работы: «{0}»  ', CourseWorkTheme);
 
 
 
  writeFormat('Образовательная степень: {0}', StringEduModel(EduModel));
 
end;
 
 
 
procedure SeniorStudent.Println;
 
begin
 
  Print;
 
  writeln();
 
end;
 
 
 
end.
 
</source>}}
 

Версия 20:11, 8 мая 2009

Наследование

Введение

Иерархическая классификация животных в биологии

Наследование в программировании возникло как ответ на реальные отношения наследования классов в реальном мире и прикладных задачах.

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

Пример. Главный алгоритм работы операционной системы.

* начальная инициализация
* цикл обработки сообщений
    если сообщение пришло то 
      обработать сообщение 
    до сообщения «Конец»
* заключительные действия

Как видим, этот алгоритм тривиален и ничего не говорит о том, как работает ОС.
————————————

Поскольку главный алгоритм сложной системы не существует или тривиален, то для программирования работы этой сложной системы мы:

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

Примеры зависимостей между классами

  1. класс содержит в качестве поля объект другого класса
  2. в методе класса параметром является объект другого класса
  3. метод класса вызывает статический метод другого класса
  4. один из классов является разновидностью другого

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

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

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

  • базовыйпроизводный
  • предокпотомок
  • надклассподкласс

Каковы цели наследования?

  1. Повторное использование кода.
  2. Обеспечение вариабельности и изменчивости кода.

Наследование — это расширение или сужение?
Наследование — это расширение интерфейса класса, но сужение количества объектов (представителей) класса.

Наследование на примере Student - SeniorStudent

Про переменную Self см. здесь.

Рассмотрим следующий пример наследования:

Пример наследования

Класс SeniorStudent (студент старших курсов) является разновидностью класса Student. Будем считать, что на младших курсах студент еще не знает, сколько лет он будет учиться и какую квалификацию получит, поэтому считается, что он учится 4 года. Будем также считать, что он узнает модель обучения (бакалавр, специалист, магистр), когда становится студентом старших курсов (SeniorStudent). В этот же момент к нему прикрепляется научный руководитель из числа преподавателей (Teacher).

<xh4> Базовый класс Student </xh4>

interface
uses System;
   
const
  /// Минимальный допустимый возраст студента
  MIN_AGE = 1;
  /// Максимальный допустимый возраст студента
  MAX_AGE = 120;

type
  /// Студент
  Student = class
  private
    fName: string;
    fAge, fCourse, fGroup: integer;
    
    procedure SetName(Name: string);
    procedure SetAge(Age: integer);
    procedure SetCourse(Course: integer);
    procedure SetGroup(Group: integer);
    
    procedure IncAge;
    
  public
    /// Имя — только на чтение
    property Name: string read fName;
    /// Возраст — только на чтение
    property Age: integer read fAge;
    /// Курс — только на чтение
    property Course: integer read fCourse;
    /// Группа — только на чтение
    property Group: integer read fGroup;
    
    constructor Create(Name: string; Age, Course, Group: integer);
    
    procedure NextCourse;
    
    procedure Print;
    procedure Println;
  end;
  
implementation

procedure Student.SetName(Name: string);
begin
  if Name <> '' then
    fName := Name
  else
    raise new Exception(
    'Попытка присвоить студенту пустое имя!');
end;

procedure Student.SetAge(Age: integer);
begin
  if (Age >= MIN_AGE) and (Age <= MAX_AGE) then
    fAge := Age
  else
    raise new Exception(
    'Выход за границы диапазона допустимого возраста [' + 
    MIN_AGE.ToString + '..' + MAX_AGE.ToString + ']!');
end;

procedure Student.SetCourse(Course: integer);
begin
  if (Course >= 1) and (Course <= 4) then
    fCourse := Course
  else
    raise new Exception(
    'Выход за границы диапазона допустимых курсов [1..4]!');
end;

procedure Student.SetGroup(Group: integer);
begin
  if (Group > 0) then
    fGroup := Group
  else
    raise new Exception(
    'Попытка присвоить группе отрицательный номер!');
end;

procedure Student.IncAge;
begin
  if fAge < MAX_AGE then
    fAge += 1
  else
    raise new Exception(
    'Выход за границы диапазона допустимого возраста [' + 
    MIN_AGE.ToString + '..' + MAX_AGE.ToString + ']!');
end;

constructor Student.Create(Name: string; Age, Course, Group: integer);
begin
  SetName(Name);
  SetAge(Age);
  SetCourse(Course);
  SetGroup(Group);
end;

procedure Student.NextCourse;
begin
  if fCourse < 4 then
  begin
    fCourse += 1;
    IncAge;
  end
  else
    raise new Exception(
    'Выход за границы диапазона допустимых курсов [1..4]!');
end;

procedure Student.Print;
begin
  WriteFormat('Имя: {0}  Возраст: {1}  Курс: {2}  Группа: {3}',
    fName, fAge, fCourse, fGroup);
end;

procedure Student.Println;
begin
  Print;
  writeln();
end;

<xh4> Производный класс SeniorStudent </xh4> SeniorStudent — студент старших курсов.
Помимо имени, возраста, курса и группы:

  • у него будет научный руководитель (Advisor: Teacher)
  • он будет знать тему курсовой работы, которую получает от своего научного руководителя
  • и для него будет известно, какую он получает академическую степень Degree (бакалавра, специалиста или магистра)

Будем считать, что класс преподавателя у нас уже есть, и есть метод SayCourseWorkTheme(MyStudent: SeniorStudent): string (можно будет сделать заглушку класса Teacher).

Приступим к реализации SeniorStudent.
Для начала нам понадобится вспомогательный тип DegreeType (академическая степень):

type
  /// Академическая степень (Бакалавр, Специалист, Магистр)
  DegreeType = (Bachelor, Specialist, Magister);

Теперь напишем интерфейс нашего старшекурсника:

  /// Студент старших курсов
  SeniorStudent = class (Student)
  private
    fAdvisor: Teacher;
    fDegree: DegreeType;
    fCourseWorkTheme: string;
    
    procedure SetAdvisor(Advisor: Teacher);
    procedure SetDegree(Degree: DegreeType);
    
    /// Устанавливает тему курсовой работы, получая её от научного руководителя
    procedure GetCourseWorkTheme;
    
  public
    /// Научный руководитель — только на чтение
    property Advisor: Teacher read fAdvisor;
    /// Образовательная степень — только на чтение
    property Degree: DegreeType read fDegree;
    /// Тема курсовой работы — только на чтение
    property CourseWorkTheme: string read fCourseWorkTheme;
    
    constructor Create(Name: string; Age, Course, Group: integer; 
      Advisor: Teacher; Degree: DegreeType);
    
    procedure NextCourse;
    
    procedure Print;
    procedure Println;
  end;

Как реализовать сеттеры, GetCourseWorkTheme и NextCourse мы знаем:

procedure SeniorStudent.SetAdvisor(Advisor: Teacher);
begin
  fAdvisor := Advisor;
end;

procedure SeniorStudent.SetDegree(Degree: DegreeType);
begin
  fDegree := Degree;
end;

procedure SeniorStudent.GetCourseWorkTheme;
begin
  fCourseWorkTheme := fAdvisor.SayCourseWorkTheme(self);
end;

procedure SeniorStudent.NextCourse;
begin
  var maxCourse: integer;
  case fDegree of
    Bachelor: maxCourse:= 4;
    Specialist: maxCourse:= 5;
    Magister: maxCourse:= 6;
  end;

  if fCourse < maxCourse then
  begin
    fCourse += 1;
    IncAge;
  end
  else
    raise new Exception(
    'Выход за границы диапазона допустимых курсов [' + 
    MIN_COURSE.ToString + '..' + maxCourse.ToString + ']!');
end;

Замечание. В процессе разработки возникла проблема доступа к приватным полям предка (fCourse)
Если Student и SeniorStudent реализованы в одном модуле, то такой проблемы нет и доступ возможен, однако, если они они реализованы в разных модулях, то данный код не откомпилируется.
Исправим это в дальнейшем, а пока будем считать, что классы реализованы в одном модуле.

Заметим, что процедура NextCourse была полностью переопределена в потомке.
Но, как правило, одноименный метод в потомке не переписывается полностью, а вызывает соответствующий метод предка.

Переопределяющий метод называется также заменяющим.

Для вызова в методе Method замещенного метода предка используется конструкция

inherited Method

Inherited — значит унаследованный.

Воспользуемся этим при реализации оставшихся методов:

constructor SeniorStudent.Create(Name: string; Age, Course, Group: integer; 
  Advisor: Teacher; Degree: DegreeType);
begin
  inherited Create(Name, Age, Course, Group);
  fAdvisor := Advisor;
  fDegree := Degree;
  GetCourseWorkTheme;
end;

procedure SeniorStudent.Print;
begin
  inherited Print;
  
  write('Преподаватель: ');  
  fAdvisor.Print;
  writeFormat('Тема курсовой работы: «{0}»  ', fCourseWorkTheme);
  
  write('Образовательная степень: ');
  case fDegree of
    Bachelor:   write('Бакалавр');
    Specialist: write('Специалист');
    Magister:   write('Магистр');
  end;
end;

procedure SeniorStudent.Println;
begin
  Print;
  writeln();
end;

Заметим, что можно выделить две дополнительных функции для работы с академической степенью:

  • function MaxCourseByDegree(degree: DegreeType): integer,
    возвращающую максимальный курс, соответствующий образовательной степени degree
  • function StringDegree(degree: DegreeType): string,
    возвращающую строковое представление академической степени («Бакалавр», «Специалист» или «Магистр»)

и использовать их в методах SeniorStudent.NextCourse и SeniorStudent.Print.