Основы программирования — второй семестр 08-09; Михалкович С.С.; IIа часть
Содержание
Введение в классы
Отличие классов от записей
Рассмотрим запись студент:
type
Student = record
name: string;
age: integer;
procedure Init(n: string; a: integer);
begin
name := n;
age := a;
end;
procedure Print;
begin
writelnFormat('Имя: {0} Возраст: {1}',
name, age);
end;
end;
var
s: student;
begin
s.Init('Иванов', 18);
end.
Когда мы описываем переменную типа Student, соответствующая ей ячейка памяти отводится на программном стеке.
А вот так выглядит класс Student:
type
Student = class
name: string;
age: integer;
constructor Create(n: string; a: integer);
begin
name := n;
age := a;
end;
procedure Print;
begin
writelnFormat('Имя: {0} Возраст: {1}',
name, age);
end;
end;
var
s: Student;
begin
s := new Student('Иванов', 18);
s.Print;
end.
Переменная типа класс хранит ссылку на объект, память под который выделяется динамически при вызове конструктора. В памяти ссылка представляется как указатель - хранит адрес объекта. Однако, такой "указатель" как бы всегда разыменован (не надо писать s^). Если переменная типа класс представляет собой ссылку. то говорят. что в языке программирования реализована ссылочная объектная модель. В большинстве современных универсальных ЯП реализована именно ссылочная объектная модель (C#, Java, Delphi). Исключение составляет C++, в котором реализована размерная объектная модель.
является указателем. Для выделения динамической памяти под объект класса Student используется вызов специального метода, называемого конструктором (New Student(<имя>, <возраст>)).
Переменная Self
Внутри каждого нестатического метода имеется переменная Self, принадлежащая к типу данного класса и являющаяся ссылкой «на себя», т.е. на объект класса, вызывающий этот метод.
Поэтому возможно написать, например, так:
type
/// Студент
Student = class
/// Имя
Name: string;
/// Возраст
Age: integer;
/// Курс
Course: integer;
/// Группа
Group: integer;
constructor (Name: string; Age, Course, Group: integer);
begin
Self.Name := Name;
Self.Age := Age;
Self.Course := Course;
Self.Group := Group;
end;
end;
Оказывается, во-первых, компилятор добавляет переменную Self в качестве первого параметра любого нестатического метода.
Во-вторых, при обращении к любому полю класса внутри метода, перед этим полем неявно добавляется Self.
Лекция 4
Шаблоны классов
type
Point<T> = class
x, y: T;
constructor(x, y: T);
begin
Self.x := x;
Self.y := y;
end;
end;
begin
var p1 : Point<real>;
var p2 : Point<integer>;
p1 := new Point<real>(2.3, 5.7);
p2 := new Point<integer>(2, 7);
p1.x := 2;
p2.x := 1.5; // ошибка компиляции, т.к.
// тип поля x объекта класса Point<integer> (integer)
// не совместим по присваиваиванию с вещественным типом real
//можем пользоваться автоопределением типов:
var p3 := new Point<real>(3.14, 7.9);
end.
Тип Point<T> называют обобщенным типом.
Теперь рассмотрим присваивание объектов класса:
var p11 := new Point<real>(0, 1.5);
var p12 := new Point<real>(2.3, 5);
p11 := p12; // происходит присваивание ссылок:
// p11 теперь указывает на тот же объект, что и p12;
// область памяти, на которую до этого указывал p11 более недоступна
var p2 := new Point<integer>(5, 7);
p11 := p2; // ошибка
// типы объектов не совпадают
При присваивании же друг другу записей, происходит копирование самих записей.
Сборка мусора
(Garbage collection)
Мусор — любые ненужные объекты.
Под ненужными понимаются объекты, которые занимают память, но недоступны в программе.
Сборка мусора — процесс освобождения памяти, занятой ненужными объектами.
Обычно, сборка мусора запускается при нехватке места в памяти. Это позволяет не заботиться об утечках памяти, т.к. все выделенное — освободится. (При этом, от всех остальных ошибок мы не застрахованы!!!)
Главный недостаток механизма сборки мусора — во время сборки выполнение программы приостанавливается.