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

Материал из Вики ИТ мехмата ЮФУ
Перейти к: навигация, поиск
(Два варианта использования операций is и as)
 
(не показаны 32 промежуточные версии 8 участников)
Строка 61: Строка 61:
  
 
Статические конструкторы в PascalABC.NET, Java.
 
Статические конструкторы в PascalABC.NET, Java.
 +
 
Класс Динамический массив (PascalABC.NET).
 
Класс Динамический массив (PascalABC.NET).
  
Строка 68: Строка 69:
  
 
Понятие итератора. Защита доступа. Интерфейс итератора. Итерация по списку с помощью итератора. Итерация с помощью foreach.
 
Понятие итератора. Защита доступа. Интерфейс итератора. Итерация по списку с помощью итератора. Итерация с помощью foreach.
 +
 
Класс Множество на PascalABC.NET. Реализация с помощью списков и с помощью бинарных деревьев поиска.
 
Класс Множество на PascalABC.NET. Реализация с помощью списков и с помощью бинарных деревьев поиска.
  
Строка 137: Строка 139:
  
 
Перегрузка операций в PascalABC.NET (на примере класса Frac).
 
Перегрузка операций в PascalABC.NET (на примере класса Frac).
 +
 
Агрегация класов и подобъекты (C++).
 
Агрегация класов и подобъекты (C++).
  
Строка 145: Строка 148:
 
Порядок вызова конструкторов и деструкторов.
 
Порядок вызова конструкторов и деструкторов.
  
Клонирование и присваивание объектов в языках со ссылочной моделью хранения объектов (на примере PascalABC.NET)  
+
Клонирование и присваивание объектов в языках со ссылочной моделью хранения объектов (на примере PascalABC.NET)
  
 
==Лекция 10 (11.11.08)==
 
==Лекция 10 (11.11.08)==
Строка 170: Строка 173:
 
Напишем классы Queue<T> и CountingQueue<T> с использованием включения (PABC.NET). Понятие делегирования. Достоинства наследования. Пример плохого использования наследования:
 
Напишем классы Queue<T> и CountingQueue<T> с использованием включения (PABC.NET). Понятие делегирования. Достоинства наследования. Пример плохого использования наследования:
  
 +
<source lang="delphi">
 
  Circle = class( Point );
 
  Circle = class( Point );
 +
</source>
  
 
В обоих классах есть реализация конструктора и процедуры Draw.
 
В обоих классах есть реализация конструктора и процедуры Draw.
Строка 179: Строка 184:
  
 
Наследование и выявление общего предка.
 
Наследование и выявление общего предка.
Даны UML-нотации классов Student и Teacher. Заметим, что у них есть общие поля и методы. Решаем вынести их в базовый класс Person. Реализовали класс Teacher на Java, в т. ч. конструктор c super(...).
+
Даны UML-нотации классов <tt>Student</tt> и <tt>Teacher</tt>. Заметим, что у них есть общие поля и методы. Решаем вынести их в базовый класс Person. Реализовали класс Teacher на Java, в т. ч. конструктор c super(...).
  
Вид доступа protected.
+
<h3>Вид доступа protected</h3>
 
Что значит protected. protected нарушает инкапсуляцию. Пример наследования Square от Rectangle на PABC.NET. Приходим к выводу, что иногда необходимо обращаться к полям и в этом случае следует использовать protected.
 
Что значит protected. protected нарушает инкапсуляцию. Пример наследования Square от Rectangle на PABC.NET. Приходим к выводу, что иногда необходимо обращаться к полям и в этом случае следует использовать protected.
  
Класс Object — предок всех классов.
+
<h3>Класс Object — предок всех классов</h3>
 
Дан интерфейс класса Object в Java и .NET (не полный - из 4 и 3 методов соответственно).
 
Дан интерфейс класса Object в Java и .NET (не полный - из 4 и 3 методов соответственно).
  
Строка 190: Строка 195:
 
Описаны переменные s (Student) и p (Person). Пытаемся одному присвоить другое. Делаем вывод, что переменная производного класса может быть неявно преобразована к типу базового класса, но не наоборот. Рассматриваем случай явного приведения типов. Вводятся понятия UpCast и DownCast.
 
Описаны переменные s (Student) и p (Person). Пытаемся одному присвоить другое. Делаем вывод, что переменная производного класса может быть неявно преобразована к типу базового класса, но не наоборот. Рассматриваем случай явного приведения типов. Вводятся понятия UpCast и DownCast.
  
Операции is и as (PABC.NET) и instanceof (Java).
+
<h3>Операции is и as (PABC.NET) и instanceof (Java)</h3>
 
Определения статического и динамического типа переменной.
 
Определения статического и динамического типа переменной.
  
===Два варианта использования операций is и as===
+
<h4>Два варианта использования операций is и as</h4>
  
 
'''Вариант 1.'''
 
'''Вариант 1.'''
  
 
''PascalABC.NET''
 
''PascalABC.NET''
 +
<source lang="delphi">
 
  if p is Student then  // не точное совпадение типов, а то, является ли p разновидностью Student
 
  if p is Student then  // не точное совпадение типов, а то, является ли p разновидностью Student
 
   Student(p).ChangeCourse(4);
 
   Student(p).ChangeCourse(4);
 +
</source>
  
 
''Java''
 
''Java''
 +
<source lang="java">
 
  if (p instanceof Student)
 
  if (p instanceof Student)
 
   ((Student)p).changeCourse(4);
 
   ((Student)p).changeCourse(4);
 +
</source>
  
 
'''Вариант 2.'''
 
'''Вариант 2.'''
  
 
''PascalABC.NET''
 
''PascalABC.NET''
 +
<source lang="delphi">
 
  var s: Student := p as Student;
 
  var s: Student := p as Student;
 +
</source>
  
 
''Java''
 
''Java''
 +
<source lang="java">
 
  Student st = (Student) p;
 
  Student st = (Student) p;
 +
</source>
  
 
==Лекция 12 (25.11.08)==
 
==Лекция 12 (25.11.08)==
  
Наследование в С++.
+
<h3>Наследование в С++</h3>
 
Вспомним наш излюбленный пример наследования на примере классов Person и Student. В предположении, что класс Person уже описан, опишем на С++ класс Student. Одно из полей Student типа char*. Понятие публичного наследования. Особенности вызова конструктора (деструктора) предка в конструкторе (деструкторе) потомка.
 
Вспомним наш излюбленный пример наследования на примере классов Person и Student. В предположении, что класс Person уже описан, опишем на С++ класс Student. Одно из полей Student типа char*. Понятие публичного наследования. Особенности вызова конструктора (деструктора) предка в конструкторе (деструкторе) потомка.
 
Пример использования char* надуман! Не пытайтесь повторить это дома!
 
Пример использования char* надуман! Не пытайтесь повторить это дома!
  
Совместимость по присваиванию и преобразование типов в иерархии Предок–Потомок.
+
<h4>Совместимость по присваиванию и преобразование типов в иерархии Предок–Потомок</h4>
 
Описали переменные p (Person) и s (Student). Они хранятся на стеке (размерная модель). Пытаемся присвоить одному другое. Делаем вывод об отбрасывании дополнительных полей производного класса при присваивании.
 
Описали переменные p (Person) и s (Student). Они хранятся на стеке (размерная модель). Пытаемся присвоить одному другое. Делаем вывод об отбрасывании дополнительных полей производного класса при присваивании.
  
Совместимость по присваиванию для типов указателей и ссылок.
+
<h4>Совместимость по присваиванию для типов указателей и ссылок</h4>
 
Присвоение указателям (ссылкам): UpCast - неявно, DownCast - только явно (с помощью операции static_cast).
 
Присвоение указателям (ссылкам): UpCast - неявно, DownCast - только явно (с помощью операции static_cast).
  
 
Конструктор копии и оператор присваивания для класса Student.
 
Конструктор копии и оператор присваивания для класса Student.
  
Полиморфизм и виртуальные функции.
+
<h3>Полиморфизм и виртуальные методы</h3>
 
(Java) Пусть в классах Person и Student есть метод print().
 
(Java) Пусть в классах Person и Student есть метод print().
  
Замещение (переопределение) методов.
+
Рассмотрим код:
 +
 
 +
<source lang="delphi">
 +
Person p = new Student(...);
 +
p.print();
 +
</source>
  
Person p = new Student(...); p.print();
+
Метод print() какого класса будет вызван? В Java - класса Student, а в OP и C++ (по умолчанию) - класса Person.  
  
Метод print() какого класса будет вызван? В Java - класса Student, а в OP и C++ (по умолчанию) - класса Person. Понятия раннего и позднего связывания.
+
Понятия раннего и позднего связывания.
  
 
Реализация позднего связывания на OP.
 
Реализация позднего связывания на OP.
Строка 246: Строка 264:
 
==Лекция 13 (02.12.08)==
 
==Лекция 13 (02.12.08)==
  
<h3>Виртуальные функции как блоки для замены кода</h3>
+
<h3>Виртуальные методы как блоки для замены кода</h3>
 
1. При разработке базового класса надо думать о будущем коде.
 
1. При разработке базового класса надо думать о будущем коде.
  
Строка 321: Строка 339:
  
 
Определение интерфейса. Описание основных интерфейсов. Пример объявления класса, поддерживающего некоторые интерфейсы.
 
Определение интерфейса. Описание основных интерфейсов. Пример объявления класса, поддерживающего некоторые интерфейсы.
 +
 +
==Лекция 15 (16.12.08)==
 +
 +
Пример реализации интерфейса в Java (класс Student реализует ICloneable).
 +
 +
<h3>Интерфейсы, совместимость по присваиванию, преобразование типов, цепочки виртуальности</h3>
 +
 +
(все последующие примеры в .NET)
 +
 +
Пример реализации интерфейса (класс Student реализует ICloneable). Описание переменной типа интерфейс. Правила присваивания ей объектов различных классов. Полиморфный контейнер объектов, поддерживающих интерфейс ICloneable. Цепочка виртуальности, задаваемая интерфейсом.
 +
 +
<h3>UpCast, DownCast и CrossCast для интерфейсов</h3>
 +
 +
Написали два интерфейса и реализующий их класс.
 +
<source lang="delphi">
 +
var im1: IMy1;
 +
    im2: IMy2;
 +
    m  : MyClass;
 +
begin
 +
    im1 := m;            // UpCast    - неявно
 +
    m  := MyClass(im2);  // DownCast  - только явно
 +
    im2 := IMy2(im1);    // CrossCast - только явно
 +
end;</source>
 +
 +
<h3>Наследование интерфейса и наследование реализации</h3>
 +
 +
Понятия наследования интерфейса и наследования реализации. В каких случаях предпочтительнее наследование интерфейса, а в каких наследование реализации? Пример наследования от многих классов (как бы он мог выглядеть в .NET), проблемы такого наследования и решение проблем с помощью интерфейсов.
 +
 +
<h3>Принцип подстановки</h3>
 +
 +
Во всех ситуациях, в которых может использоваться объект базового класса, можно подставить объект производного класса без потери функциональности.
 +
 +
Принцип подстановки выполняется не всегда. Например, при наследовании с ограничением (круг от эллипса или вектор от матрицы) принцип подстановки не выполняется.
 +
 +
Принцип подстановки всегда выполняется если используется полиморфизм, а также при наследовании интерфейса.
 +
 +
<h3>Стандартные интерфейсы .NET</h3>
 +
 +
Пример 1. Интерфейс IComparable и его использование.
 +
 +
Пример 2. Интерфейс IComparer и его использование.
 +
 +
==Лекция 16 (23.12.08)==
 +
 +
<h3>Исключения</h3>
 +
 +
<h4>Исключения в PABC.NET</h4>
 +
 +
Задача 1. Есть набор файлов текстового формата. Эти файлы содержат целые числа, разделенные пробелами и символами перехода на новую строку. Пользователь вводит имя файла. Программа выдает сумму чисел в файле.
 +
 +
Решение.
 +
Начнем с самой вложенной функции.
 +
<source lang="delphi">
 +
function EvalSum( data: Text ): integer;
 +
begin
 +
  Result := 0;
 +
  while not SeekOEof(data) do
 +
  begin
 +
      var a: integer;
 +
      Read( data, a ); // Проблема 2
 +
      Result += a;
 +
  end;
 +
end;</source>
 +
Функция обработки файла
 +
<source lang="delphi">
 +
function ProcessFile( fName: string ):integer;
 +
begin
 +
  var f: text;
 +
  Assign( f, fName );
 +
  Reset(f);          // Проблема 1
 +
  Result := EvalSum(f);
 +
  Close(f);
 +
end;</source>
 +
Далее напишем бесконечный цикл, в котором будем спрашивать у пользователя имя файла и обрабатывать его.
 +
Итого: имеем две проблемы:
 +
 +
проблема 1: Файл может не существовать.
 +
проблема 2: В файле могут быть неправильные данные.
 +
 +
Решение 1 проблемы 1. Можно поставить перед Reset(f) условный оператор
 +
<pre>Если файл существует
 +
      открой его на чтение</pre>
 +
Сейчас, когда мы работаем в многозадачной среде может быть такое, что кто-то удалил файл после выполнения if'а, но перед Reset.
 +
Это плохое решение.
 +
 +
Решение 1 проблемы 2. Можно считывать не integer, а string и пытаться преобразовать к интам, Но проблема вот в чем: если мы не смогли преобразовать, придется написать
 +
<source lang="delphi">Writeln('Ошибка');</source>
 +
А что если EvalSum используется в оконном приложении? Куда выведется результат? В воздух?
 +
 +
Решение 2 проблемы 2. Пусть функция возвращает код ошибки.
 +
Для этого были придуманы исключения.
 +
 +
В коде с комментарием Проблема PABC.NET генерирует исключение.
 +
<source lang="delphi">
 +
while true do
 +
begin
 +
  var fName : string;
 +
  Realdn( fName );
 +
  try
 +
      var sum := ProcessFile(fName);
 +
      writeln(sum);
 +
  except
 +
      Writeln('Ошибка'); // Хотелось бы поконкретней
 +
  end;
 +
end;</source>
 +
 +
Понятия try-блока и секции обработки исключений.
 +
<source lang="delphi">
 +
try
 +
  var sum := ProcessFile(fName);
 +
  writeln(sum);
 +
except
 +
  on System.IO.FileNotFoundException do
 +
      Writeln('Файл отсутствует');
 +
 +
  on System.FormatException do
 +
      Writeln('Неверный формат файла');
 +
end;</source>
 +
 +
 +
'''То,_что_надо_отвечать_на_экзамене_на_вопросы,_касательные_исключений'''
 +
 +
Генерация исключения прерывает нормальное выполнение подрограммы и приводит к раскрутке стека вызовов вплоть до обнаружения соответствующего try-блока.
 +
<source lang="delphi">
 +
try
 +
  ...
 +
except
 +
  on ... do  ...
 +
  on ... do  ...
 +
 +
  ...
 +
 +
  else
 +
    ...
 +
end;</source>
 +
 +
В таком try-блоке будут обработаны все исключения без исключения(c).
 +
 +
Закрыть файл мы можем только там, где открыли.
 +
<source lang="delphi">
 +
function ProcessFile( fName: string ):integer;
 +
begin
 +
  var f: text;
 +
  Assign( f, fName );
 +
  Reset(f);
 +
  try
 +
      Result := EvalSum(f);
 +
  finally
 +
      Close(f); // действия в блоке finally будут выполнены не зависимо от исключения
 +
  end;
 +
end;</source>
 +
 +
Задача 2. Модифицируем задачу 1. Предположим все целые числа разделены двоеточием.
 +
В этом случае все содержимое файла будет записано в строку.
 +
Решение.
 +
Считаем строку, разделим ее методом Split. Получившийся массив в цикле foreach будем парсить в integer.
 +
<source lang="delphi">
 +
if not Integer.TryParse(str, number) then // Если формат файла не верный
 +
  raise new System.FOrmatException;      // то сгенерируем исключение</source>
 +
'''Исключение''' - это объект определенного класса.
 +
Все исключения, которые можно выбрасывать, являются классами System.Exception.
 +
 +
'''Ужасная вещь, которую надо написать, а потом аккуратненько потолще зачеркнуть'''
 +
 +
Пример необоснованного использования исключений.
 +
 +
Для создания своего исключения достаточно сделать потомок класса Exception.
 +
 +
<h4>Исключения в Java</h4>
 +
 +
Иерархия исключений. Контролирумое исключение, неконтролирумое исключение. Объявление исключения. Блоки try - catch и try - finally.
 +
 +
<h4>Исключения в С++</h4>
 +
 +
Все не как у всех.
 +
- Выбрасывать можно все что угодно (даже Зоопарк).
 +
- Исключения генерируются по значению, а перехватываются по ссылке.
 +
- finally нет. Это связано с тем, что когда идет развертка стека автоматически вызываются деструкторы.
 +
 +
Стандартные способы обработки исключений
 +
 +
==Ссылки==
 +
*[[Конспекты|Другие конспекты]]
 +
[[Категория:Конспекты]]
 +
[[Категория:Языки программирования]]

Текущая версия на 18:04, 4 июня 2009

Содержание

Лекция 1

Основы Java. Понятие виртуальной машины, схема компиляции и выполнения. Преимущества и недостатки виртуальной машины.

Первая программа на Java.

Переменные и константы. Стандартные типы. Правила приведения числовых типов.

Ввод-вывод. Класс Scanner.

Операторы.

Перечислимый тип.

Класс String, некоторые его методы.

Массивы. Оператор for(x: a). Класс java.util.Arrays.

Двумерные массивы.

Функции. Параметры. Отсутствие ссылочных параметров.

Лекция 2

АТД. Интерфейс, реализация, принцип сокрытия реализации.

Реализация АТД в виде класса.

Класс как модуль и как тип данных.

Инкапсуляция как объединение методов и полей в одной "капсуле".

Защита доступа в классе (private, public).

Синтаксис классов в PABC.NET и в Java. Вызов конструкторов.

Определение методов внутри и вне интерфейса класса (PascalABC.NET). Достоинства и недостатки каждого способа.

Класс Стек и его реализация на основе массива (PascalABC.NET, Java). Клиентская программа для класса Стек (PascalABC.NET, Java).

Вывод: семантика классов в PascalABC.NET и Java практически идентична, различается только синтаксис.

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

Передача параметров по ссылке в Java - необходимость создания класса-обертки.

Лекция 3 (16.09.08)

Размерная модель классов в C++. Хранение объектов классов в памяти. Присваивание объектов.

Определение методов внутри и вне интерфейса класса (C++).

Где следует размещать код интерфейса класса и код реализации его методов.

Методы в записях PascalABC.NET. Размерная модель данных для записей.

Объекты C++ в динамической памяти. Необходимость явного освобождения памяти.

Лекция 4 (23.09.08)

Статические методы и поля в PascalABC.NET, Java и C++.

Статические конструкторы в PascalABC.NET, Java.

Класс Динамический массив (PascalABC.NET).

Свойства. Свойства с индексами.

Стандартный класс двусвязного списка в библиотеке .NET.

Понятие итератора. Защита доступа. Интерфейс итератора. Итерация по списку с помощью итератора. Итерация с помощью foreach.

Класс Множество на PascalABC.NET. Реализация с помощью списков и с помощью бинарных деревьев поиска.

Идея ускорения доступа. Хеширование. Хеш-таблица, хеш-функция.

Лекция 5 (30.09.08)

Реализация множества на основе хеш-таблицы.

Класс Ассоциативный массив на PascalABC.NET на основе списка.

Классы ассоциативных массивов в стандартной библиотеке NET. Итератор ассоциативного массива. Цикл foreach по ассоциативному массиву.

Контейнерные классы в Java: обзор. Классы-обертки (Integer, Double).

Стандартный класс двусвязного списка в библиотеке Java. Итератор списка. Итерация по списку.

Пакеты в Java. Пример использования пакетов.

Лекция 6 (07.10.08)

Библиотеки в PascalABC.NET. Многоязыковость. Отличие библиотек от модулей.

Библиотеки JAR в Java.

Перегрузка операций в C++ - общие правила.

Класс Date. Перегрузка операций +, +=, ++ (префиксной и постфиксной), ==, !=.

Дружественные функции в C++.

Лекция 7 (14.10.08)

Перегрузка операций << и >>

С++: выделение динамической памяти в конструкторе (на примере класса myvector).

Перегрузка операции [].

Деструкторы. Момент вызова деструктора.

Динамический массив в динамической памяти. Момент вызова конструктора и деструктора.

Моделирование ссылочной модели данных средствами C++.

Конструктор копии. КК, генерируемый по умолчанию. Когда его не достаточно.

Операция присваивания. Операция присваивания, генерируемая по умолчанию.

Ситуации, в которых вызывается конструктор копии.

Лекция 8 (21.10.08)

Шаблон класса myvector<T>. Особенности компиляции шаблонов. Где надо размещать описания шаблонов и почему.

Описание функции-члена вне интерфейса класса.

Понятие инстанцирования шаблона класса. Два уровня ошибок компиляции шаблонов: при компиляции собственно шаблона и в момент инстанцирования шаблона.

Массив объектов класса и роль конструктора по умолчанию.

Операция (). Примеры: реализация класса matrix и объекты-функции. Преимущества объектов-функций.

Лекция 9 (28.10.08)

Класс frac. Конструктор преобразования и операция приведения типа.

Ключевое слово explicit и запрет неявного преобразования.

Перегрузка операций в PascalABC.NET (на примере класса Frac).

Агрегация класов и подобъекты (C++).

Вызов конструктора подобъекта.

Роль конструктора по умолчанию.

Порядок вызова конструкторов и деструкторов.

Клонирование и присваивание объектов в языках со ссылочной моделью хранения объектов (на примере PascalABC.NET)

Лекция 10 (11.11.08)

Наследование. Основные определения: базовый класс-производный класс, предок-потомок, надкласс-подкласс. Цели наследования. Описание на PABC.NET классов Student и SeniorSudent (наследник Student).

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

Переопределение и замещающие функции (PABC.NET). Ключевое слово inherited.

Вызов конструктора предка в конструкторе потомка (PABC.NET). Конструктор для SeniorSudent. Рекомендуется вызывать конструкторы предков первыми в конструкторе потомка, т.к. объект предка д.б. создан перед какими-то следующими действиями. В большинстве языков программирования конструкторы предка вызываются первыми принудительно. В качестве примера написали классы Queue<T> и CountingQueue<T> (наследник Queue с одним дополнительным полем - количеством элементов).

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

Наследование и включение. Понятие включения (физического и логического). Изображение отношений наследования и включения на UML-диаграммах.

Что выбрать — наследование или включение? Напишем классы Queue<T> и CountingQueue<T> с использованием включения (PABC.NET). Понятие делегирования. Достоинства наследования. Пример плохого использования наследования:

 Circle = class( Point );

В обоих классах есть реализация конструктора и процедуры Draw.

Примеры с неоднозначным выбором наследования или включения.

Лекция 11 (18.11.08)

Наследование и выявление общего предка. Даны UML-нотации классов Student и Teacher. Заметим, что у них есть общие поля и методы. Решаем вынести их в базовый класс Person. Реализовали класс Teacher на Java, в т. ч. конструктор c super(...).

Вид доступа protected

Что значит protected. protected нарушает инкапсуляцию. Пример наследования Square от Rectangle на PABC.NET. Приходим к выводу, что иногда необходимо обращаться к полям и в этом случае следует использовать protected.

Класс Object — предок всех классов

Дан интерфейс класса Object в Java и .NET (не полный - из 4 и 3 методов соответственно).

Присваивание в иерархии Предок–потомок. Описаны переменные s (Student) и p (Person). Пытаемся одному присвоить другое. Делаем вывод, что переменная производного класса может быть неявно преобразована к типу базового класса, но не наоборот. Рассматриваем случай явного приведения типов. Вводятся понятия UpCast и DownCast.

Операции is и as (PABC.NET) и instanceof (Java)

Определения статического и динамического типа переменной.

Два варианта использования операций is и as

Вариант 1.

PascalABC.NET

 if p is Student then  // не точное совпадение типов, а то, является ли p разновидностью Student
   Student(p).ChangeCourse(4);

Java

 if (p instanceof Student)
   ((Student)p).changeCourse(4);

Вариант 2.

PascalABC.NET

 var s: Student := p as Student;

Java

 Student st = (Student) p;

Лекция 12 (25.11.08)

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

Вспомним наш излюбленный пример наследования на примере классов Person и Student. В предположении, что класс Person уже описан, опишем на С++ класс Student. Одно из полей Student типа char*. Понятие публичного наследования. Особенности вызова конструктора (деструктора) предка в конструкторе (деструкторе) потомка. Пример использования char* надуман! Не пытайтесь повторить это дома!

Совместимость по присваиванию и преобразование типов в иерархии Предок–Потомок

Описали переменные p (Person) и s (Student). Они хранятся на стеке (размерная модель). Пытаемся присвоить одному другое. Делаем вывод об отбрасывании дополнительных полей производного класса при присваивании.

Совместимость по присваиванию для типов указателей и ссылок

Присвоение указателям (ссылкам): UpCast - неявно, DownCast - только явно (с помощью операции static_cast).

Конструктор копии и оператор присваивания для класса Student.

Полиморфизм и виртуальные методы

(Java) Пусть в классах Person и Student есть метод print().

Рассмотрим код:

 Person p = new Student(...); 
 p.print();

Метод print() какого класса будет вызван? В Java - класса Student, а в OP и C++ (по умолчанию) - класса Person.

Понятия раннего и позднего связывания.

Реализация позднего связывания на OP. Виртуальные методы. Модификатор virtual и ключевое слово override. Определение полиморфизма.

Реализация полиморфизма в С++. Аналогично в классах Person и Student описан метод print(). Присвоим объекту класса Person объект класса Student и вызовем для него метод print(). Вызовется print() класса Person. Сделаем метод виртуальным (virtual в заголовке). Все равно будет вызван метод класса Person. Причина: при присваивании происходит отбрасывание дополнительных полей и потеря информации о типе. Выход: полиморфизм в С++ работает только через указатели или ссылки на базовый класс.

В Java все методы (за исключением статических) виртуальные.

Лекция 13 (02.12.08)

Виртуальные методы как блоки для замены кода

1. При разработке базового класса надо думать о будущем коде.

2. Полиморфизм заставляет работать уже откомпилированный код совершенно по-другому. Определение полиморфного объекта (объекта, обладающего полиморфным поведением), полиморфной подпрогораммы.

Виртуальные методы в классе Object

В С++ нет класса, базового для всей иерархии классов. Рассмотрели пример переопределения метода ToString класса Object на PABC.NET.

Цепочки виртуальности и ее разрыв

Определение цепочки виртуальности.

Алгоритм поиска в цепочке виртуальности метода, который следует вызывать.

Разрыв цепочки виртуальности.

Идентификатор reintroduce (NET).

С++ - виртуальные деструкторы

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

Полиморфные контейнеры

Полиморфный контейнер в .NET

Рассмотрели пример на PascalABC.NET в котором Shape - это предок классов геометрических фигур. Хотим написать методы Draw и Hide. Вместо этого (вместе с этим) дали определение абстрактного метода и абстрактного класса. Идем дальше. Реализовали класс Shape. В глаза бросается метод MoveTo, который вызывает два абстрактных виртуальных метода (Hide и Draw). Интересно, он вообще работает... Ответ: да, работает, ведь перед Hide и Draw неявно стоит self - ссылка, - как раз то, что надо для виртуальных методов. Заполнили List<Shape> объектами производного от Shape класса, в одном цикле foreach нарисовали их, в другом переместили. Определение полиморфного контейнера. Если класс абстрактный, то объекты этого класса создавать нельзя.

Полиморфный контейнер на С++

Написали тот же класс Shape на С++. Здесь Hide и Draw называются уже чисто виртуальными ( =0 ). Затем заполнили vector<Shape*> объектами производного класса, в цикле (с итератором) нарисовали их, а потом еще и переметили на заданный ветктор. Полиморфное клонирование в полиморфном контейнере.

Система RTTI в С++

Если в классе не определено ни одной виртуальной функции, то аналогии is и as ввести нельзя. Аналогии операций is и as.

1. Операция dynamic_cast

dynamic_cast - это полный аналог as.

dynamic_cast<Student*>(pperson) == 0 - аналог is.

Лекция 14 (09.12.08)

2. Операция typeid и структура type_info

Посмотрим на поля и методы type_info. Попробуем повыводить на консоль typeid(выражение) и typeid(тип).

Задача (С++) о раскраске всех треугольников из vector<Shape*> - потомков класса Shape:

1-ый способ: Покрасить все треугольники и их наследников.

2-ой способ: Покрасить все треугольники, но не производные классы.

3-ий способ: Покрасить все треугольники, но не производные классы, используя только полиморфизм.

Таблица виртуальных методов - внутренний механизм реализации полиморфизма

Рассмотрели иерархию классов (A ◅— B ◅— C) с не виртуальными и виртуальными методами и с разрывом цепочки виртуальности. Объявили переменную p:

var p: A;

инициализировали:

p := new A;

Затем последовательно присвоили p ссылки на B и на C и смотрели что происходит в памяти после каждого оператора присваивания. Введены понятия VMT и vptr. Накладные расходы на вызов виртуальных методов (по памяти и по времени).

Интерфейсы (.NET и Java)

Определение интерфейса. Описание основных интерфейсов. Пример объявления класса, поддерживающего некоторые интерфейсы.

Лекция 15 (16.12.08)

Пример реализации интерфейса в Java (класс Student реализует ICloneable).

Интерфейсы, совместимость по присваиванию, преобразование типов, цепочки виртуальности

(все последующие примеры в .NET)

Пример реализации интерфейса (класс Student реализует ICloneable). Описание переменной типа интерфейс. Правила присваивания ей объектов различных классов. Полиморфный контейнер объектов, поддерживающих интерфейс ICloneable. Цепочка виртуальности, задаваемая интерфейсом.

UpCast, DownCast и CrossCast для интерфейсов

Написали два интерфейса и реализующий их класс.

var im1: IMy1;
    im2: IMy2;
    m  : MyClass;
begin
    im1 := m;             // UpCast    - неявно
    m   := MyClass(im2);  // DownCast  - только явно
    im2 := IMy2(im1);     // CrossCast - только явно 
end;

Наследование интерфейса и наследование реализации

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

Принцип подстановки

Во всех ситуациях, в которых может использоваться объект базового класса, можно подставить объект производного класса без потери функциональности.

Принцип подстановки выполняется не всегда. Например, при наследовании с ограничением (круг от эллипса или вектор от матрицы) принцип подстановки не выполняется.

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

Стандартные интерфейсы .NET

Пример 1. Интерфейс IComparable и его использование.

Пример 2. Интерфейс IComparer и его использование.

Лекция 16 (23.12.08)

Исключения

Исключения в PABC.NET

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

Решение. Начнем с самой вложенной функции.

function EvalSum( data: Text ): integer;
begin
   Result := 0;
   while not SeekOEof(data) do
   begin
      var a: integer;
      Read( data, a ); // Проблема 2
      Result += a;
   end;
end;

Функция обработки файла

function ProcessFile( fName: string ):integer;
begin
   var f: text;
   Assign( f, fName );
   Reset(f);           // Проблема 1
   Result := EvalSum(f);
   Close(f);
end;

Далее напишем бесконечный цикл, в котором будем спрашивать у пользователя имя файла и обрабатывать его. Итого: имеем две проблемы:

проблема 1: Файл может не существовать. проблема 2: В файле могут быть неправильные данные.

Решение 1 проблемы 1. Можно поставить перед Reset(f) условный оператор

Если файл существует
       открой его на чтение

Сейчас, когда мы работаем в многозадачной среде может быть такое, что кто-то удалил файл после выполнения if'а, но перед Reset. Это плохое решение.

Решение 1 проблемы 2. Можно считывать не integer, а string и пытаться преобразовать к интам, Но проблема вот в чем: если мы не смогли преобразовать, придется написать

Writeln('Ошибка');

А что если EvalSum используется в оконном приложении? Куда выведется результат? В воздух?

Решение 2 проблемы 2. Пусть функция возвращает код ошибки. Для этого были придуманы исключения.

В коде с комментарием Проблема PABC.NET генерирует исключение.

while true do
begin
   var fName : string;
   Realdn( fName );
   try
      var sum := ProcessFile(fName);
      writeln(sum);
   except
      Writeln('Ошибка'); // Хотелось бы поконкретней
   end;
end;

Понятия try-блока и секции обработки исключений.

try
   var sum := ProcessFile(fName);
   writeln(sum);
except
   on System.IO.FileNotFoundException do
      Writeln('Файл отсутствует');

   on System.FormatException do
      Writeln('Неверный формат файла');
end;


То,_что_надо_отвечать_на_экзамене_на_вопросы,_касательные_исключений

Генерация исключения прерывает нормальное выполнение подрограммы и приводит к раскрутке стека вызовов вплоть до обнаружения соответствующего try-блока.

try
  ...
except
  on ... do  ...
  on ... do  ...

   ...

  else
    ...
end;

В таком try-блоке будут обработаны все исключения без исключения(c).

Закрыть файл мы можем только там, где открыли.

function ProcessFile( fName: string ):integer;
begin
   var f: text;
   Assign( f, fName );
   Reset(f);
   try
      Result := EvalSum(f);
   finally
      Close(f); // действия в блоке finally будут выполнены не зависимо от исключения
   end; 
end;

Задача 2. Модифицируем задачу 1. Предположим все целые числа разделены двоеточием. В этом случае все содержимое файла будет записано в строку. Решение. Считаем строку, разделим ее методом Split. Получившийся массив в цикле foreach будем парсить в integer.

if not Integer.TryParse(str, number) then // Если формат файла не верный
   raise new System.FOrmatException;      // то сгенерируем исключение

Исключение - это объект определенного класса. Все исключения, которые можно выбрасывать, являются классами System.Exception.

Ужасная вещь, которую надо написать, а потом аккуратненько потолще зачеркнуть

Пример необоснованного использования исключений.

Для создания своего исключения достаточно сделать потомок класса Exception.

Исключения в Java

Иерархия исключений. Контролирумое исключение, неконтролирумое исключение. Объявление исключения. Блоки try - catch и try - finally.

Исключения в С++

Все не как у всех. - Выбрасывать можно все что угодно (даже Зоопарк). - Исключения генерируются по значению, а перехватываются по ссылке. - finally нет. Это связано с тем, что когда идет развертка стека автоматически вызываются деструкторы.

Стандартные способы обработки исключений

Ссылки