Академический Документы
Профессиональный Документы
Культура Документы
ПРОГРАММИРОВАНИЕ НА
ЯЗЫКЕ С++
Методические указания к лабораторным работам
Кишинэу-2005
Технический Университет Молдовы
Кишинэу
ТУМ
2005
Данное пособие предназначено изучению основ объектно-
ориентированного программирования на языке С++. Пособие
организованно в виде лабораторных работ, и содержит семь тем.
Каждая тема состоит как из теоретической, так и практической
частей. Пособие рекомендуется студентам специальности
Информационные Технологии, а также всем желающим изучить
язык С++ и основы ООП.
Рецензент:
Основные понятия
b1.pages = 153;
bs[i].pages = 24;
Circle1.Center.x = 20;
Circle1.Center.y = 10;
struct Date{
int day, month, year;
4
};
struct Student{
char *name;
Date birthDay;
float media;
};
Book b;
b.author = NULL;
setAuthor(&b, ”Arthur Conan Doyle”);
6
Контрольные вопросы:
7
Задания
Вариант 1
а) Создать абстрактный тип данных, для комплексных чисел
используя структуру. Определить функции установки/чтения
значений реальной и мнимой части, сложения, вычитания,
умножения, деления, сравнения (меньше, больше, и т.д.).
Определить функцию-норму комплексных чисел. Все функции
должны быть определены, как глобальные и быть
переносимыми.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на int и число элементов. Определить
функции: инициализации, удаления вектора, установки/
изменения размера, доступа к элементам вектора, вычисления
нормы вектора. Для примера, в функции main, организовать
сложение двух векторов.
Вариант 2
а) Создать абстрактный тип данных - собака, у которой есть
порода, кличка и возраст (структура). Определить функции
установки и изменения данных и удаления выделенной памяти.
Для задания текстовых полей использовать оператор new.
Определить функцию сортировки массива собак по возрасту +
кличке. То есть собаки одного возраста сортируются в
алфавитном порядке.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на float и число элементов. Определить
функции: инициализации, удаления вектора, установки/
изменения размера, доступа к элементам вектора, вычисления
суммы элементов вектора. Для примера, в функции main,
организовать поэлементное умножение двух векторов.
8
Вариант 3
а) Создать абстрактный тип данных - компьютер, содержащий
информацию о фирме-изготовителе, процессоре, тактовой
частоте и др. Определить функции установки данных, изменения
информации, сравнения. Для задания текстовых полей
использовать оператор new. Освободить выделенную память. В
функции main представить пример сортировки массива
компьютеров по полям тактовая частота + процессор.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на double и число элементов.
Определить функции: инициализации, удаления вектора,
установки/изменения размера, доступа к элементам вектора,
вычисления суммы положительных элементов вектора. Для
примера, в функции main, организовать умножение вектора на
число.
Вариант 4
а) Создать абстрактный тип данных (структура) - страна, у
которой есть название, материк на котором находится страна и
количество жителей. Определить функции установки названия
страны и количества населения, изменения данных, сравнения
стран и освобождения памяти. Для задания названия города
использовать оператор new. В main-е, привести пример поиска
городов по названию и населению.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на int и число элементов. Определить
функции: инициализации, удаления вектора, установки/
изменения размера, доступа к элементам вектора, вычисления
среднего положительных элементов вектора. Для примера, в
функции main, организовать сравнение двух векторов.
9
Вариант 5
а) Создать абстрактный тип данных (структура) - сотрудник, у
которой есть имя, специальность, разряд и заработная плата.
Определить функции установки, изменения данных и сравнения
сотрудников. Для задания текстовых полей использовать
оператор new. Освободить память. В main-е, привести пример
сортировки сотрудников по разным критериям.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на long и число элементов. Определить
функции: инициализации, удаления вектора, установки/
изменения размера, доступа к элементам вектора, вычисления
суммы отрицательных элементов вектора. Для примера, в
функции main, организовать сложение двух векторов.
Вариант 6
а) Создать абстрактный тип данных (структура) - дом, у которой
есть название фирмы строителя, адрес, количество этажей и
квартир. Определить функции установки, изменения данных,
сравнения домов. Для задания текстовых полей использовать
оператор new. Освободить память. В main-е, привести пример
сортировки домов по количеству этажей + адресу в алфавитном
порядке.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на float и число элементов. Определить
функции: инициализации, удаления вектора, установки/
изменения размера, доступа к элементам вектора, вычисления
нормы вектора. Для примера, в функции main, организовать
сложение элементов вектора и числа.
10
Вариант 7
а) Создать абстрактный тип данных (структура) - монитор, у
которой есть название фирмы производителя, размер в дюймах,
количество цветов и разрешающая способность. Определить
функции установки, изменения данных, сравнения мониторов.
Для задания текстовых полей использовать оператор new.
Освободить память. В main-е, привести пример поиска
подходящего монитора по размеру и другим данным.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на byte и число элементов. Определить
функции: инициализации, удаления вектора, установки/
изменения размера, доступа к элементам вектора, вычисления
произведения отрицательных элементов вектора. Для примера, в
функции main, организовать поэлементное умножение векторов.
Вариант 8
а) Создать абстрактный тип данных (структура) - книга, у
которой есть название, автор, издательство, объем в страницах и
год издания. Определить функции установки, изменения данных,
сравнения. Для задания текстовых полей использовать оператор
new. Освободить память. В main-е, привести пример поиска
нужной книги по названию и по автору.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на short и число элементов. Определить
функции: инициализации, удаления вектора, установки/
изменения размера, доступа к элементам вектора, вычисления
суммы четных элементов вектора. Для примера, в функции main,
организовать сравнение векторов.
11
Вариант 9
а) Создать абстрактный тип данных (структура) - студент, у
которого есть имя, специальность, год обучения и средний балл.
Определить функции установки, изменения данных, сравнения.
Для задания текстовых полей использовать оператор new.
Освободить память. В main-е, привести пример сортировки
студентов по специальностям + успеваемости.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на long и число элементов. Определить
функции: инициализации, удаления вектора, установки/
изменения размера, доступа к элементам вектора, вычисления
суммы четных элементов вектора. Для примера, в функции main,
организовать поиск позиции максимального элемента вектора.
Вариант 10
а) Создать абстрактный тип данных (структура)–программный
ресурс (software), у которого есть название, фирма
производитель, год издания и версия. Определить функции
установки, изменения данных, сравнения. Для задания текстовых
полей использовать оператор new. Освободить память. В main-е,
привести пример поиска нужного продукта по нескольким
критериям.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на double и число элементов.
Определить функции: инициализации, удаления вектора,
установки/изменения размера, доступа к элементам вектора,
вычисления суммы четных элементов вектора. Для примера, в
функции main, организовать сложение вектора и числа.
12
Вариант 11
а) Создать абстрактный тип данных (структура) - фирма, у
которой есть название, организационное форма, адрес и год
учреждения. Определить функции установки, изменения данных,
сравнения. Для задания текстовых полей использовать оператор
new. Освободить память. В main-е, привести пример поиска
нужной фирмы по нескольким критериям.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на int и число элементов. Определить
функции: инициализации, удаления вектора, установки/
изменения размера, доступа к элементам вектора, вычисления
суммы четных элементов вектора. Для примера, в функции main,
организовать сложение двух векторов.
Вариант 12
а) Создать абстрактный тип данных (структура) - файл, у
которого есть название, дата и время создания и размер.
Определить функции установки, изменения данных, сравнения.
Для задания текстовых полей использовать оператор new.
Освободить память. В main-е, привести пример сортировки
файлов по некоторым критериям.
b) Создать абстрактный тип данных (структура) - вектор,
который имеет указатель на float и число элементов. Определить
функции: инициализации, удаления вектора, установки/
изменения размера, доступа к элементам вектора, вычисления
суммы четных элементов вектора. Для примера, в функции main,
организовать поиск позиции минимального элемента вектора.
13
ЛАБОРАТОРНАЯ РАБОТА №2
Основные понятия
Мотивация
Одна из самых распространенных ошибок при
программировании (на любом языке) состоит в том, что объект
используется без предварительной инициализации, так как не все
языки обеспечивают автоматическую инициализацию. Конечно
же, можно самому определить функцию инициализации и
освобождения, как сделано в следующем примере:
class Book{
char *author;
int year;
int pages;
public:
void Init(char*, int, int);
void Destroy();
};
void Book::Init(char* a, int y, int p){
author = new char[strlen(a)+1];
strcpy(author,a);
year=y;
pages=p;
}
void Book::Destroy(){
delete[] author;
}
14
Однако такой пример сам по себе опасен, так как никто не
гарантирует, что инициализация будет произведена, или будет
освобождена занятая память. Другой недостаток данного
примера, состоит в опасности утечки памяти, так как функция
инициализации может быть вызвана неограниченное количество
раз. Так же может произойти крах системы по причине
некорректной работы с динамической памятью. Причина – вызов
функции Destroy, без инициализации.
Определение и использование
Чтобы помочь избежать этой ошибки, С++ обеспечивает
механизм автоматической инициализации для определяемых
пользователем классов - конструктор класса. А для
завершающих операций – деструктор.
Конструктор – специальная функция класса, которая
вызывается автоматически при создании объекта типа класса.
Имя конструктора совпадает с именем класса, не возвращает
никакого результата, даже void. Компилятор гарантирует
единственный вызов конструктора для одного объекта.
Деструктор – специальная функция класса, которая
вызывается автоматически при уничтожении объекта. Имя
деструктора совпадает с именем класса, перед которым ставится
символ “~”. Компилятор гарантирует единственный вызов
деструктора для одного объекта. Деструктор не может иметь
параметров и по этому не может быть перегружен.
При создании автоматической переменной деструктор
вызывается автоматически при выходе из области видимости, то
есть за рамки блока, в котором определена переменная. Для
динамических переменных дела обстоят совсем по-другому, для
освобождения занятой памяти используется оператор delete,
который и вызывает деструктор.
Приведем аналогичный первому пример с использованием
конструктора и деструктора:
15
class Book{
char *author;
int year;
int pages;
public:
Book(char*, int, int);
~Book();
};
Book::Book(char* a, int y, int p){
author = new char[strlen(a)+1];
strcpy(author,a);
year=y;
pages=p;
}
Book::~Book(){
delete[] author;
}
void main(){
Book b(“Stroustrup”,2000,890);
// Book b1; // попытка создание объекта
без // вызова конструктора
// приведет к ошибке
Типы конструкторов
Существует четыре вида конструкторов: по умолчанию,
копий, приведения типа и основной. Эта классификация
основана на правилах определения и использования
конструкторов.
16
Конструктор по умолчанию – конструктор, не имеющий
параметров, либо параметра которого имеют значения по
умолчанию.
Конструктор копий (копирования) – конструктор
получающий ссылку на объект того же типа.
Конструктор приведения типа – конструктор, приводящий
объект одного типа к другому.
Основной конструктор, – не подпадающий ни под одну из
вышеперечисленных категорий.
Приведем пример:
class Book{
char *author;
int year;
int pages;
public:
Book(); // конструктор по
// умолчанию
Book(const Book&); // конструктор копий
Book(const char*); // конструктор
// приведения типа
Book(char*, int, int); // основной
...
};
...
void main(){
Book b(“Stroustrup”,1997,890); // основной
Book b1 = b, b11(b); // копий
Book b2 = “Stroustrup”, b21(“Bjarne”);
// приведения типа
Book b3; //по умолчанию
}
Рекомендации
Каждый класс должен содержать конструктор. Если в
классе имеются поля-указатели – обязательно перегрузить
конструктор копий. Конструктор копий используется для
создания копии объекта, при передаче и возвращении по
значению объекта в/из функции. Причина перегрузки
конструктора копии состоит в необходимости использования
дополнительных действий по сравнению со стандартным
алгоритмом копирования, так как в этом случае возможна
ситуация, когда два разных объекта адресуют одну и туже
память, что может привести к потере данных и к ошибке
оперативной памяти.
Приведем пример конструкторы копий:
18
Book::Book(const Book& b): year(b.year),pages(b.pages),
author(new char[strlen(b.author)+1])
{
strcpy(author, b.author);
}
// вызов функции strcpy не удалось "запихнуть" в
// инициализатор.
Контрольные вопросы:
19
Задания
Вариант 1
а) Создать класс Date - дата с полями: день (1-28..31), месяц (1-
12), год (целые числа). Определить конструкторы, функции-
члены установки дня, месяца и года, функции-члены получения
дня, месяца и года. Также две функции печати: печать по
шаблону: "19 апреля 2003 года" и "19.04.2003". Функции
установки полей класса должны проверять корректность
задаваемых параметров.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на int, количество строк и столбцов и переменную -
код ошибки. Определить конструктор без параметров,
конструктор с одним параметром – квадратная матрица и
конструктор с двумя параметрами – прямоугольная матрица и др.
Определить методы доступа: возвращение и определение
значения элемента (i,j). Определить функции сложения и
вычитания (матрицы с матрицей), умножение матрицы на
матрицу. Определить умножение матрицы на число. Проверить
работу этого класса. В случае нехватки памяти, несоответствия
размерностей, выхода за пределы используемой памяти
устанавливать код ошибки.
Вариант 2
а) Создать класс Time - время с полями: часы (0-23), минуты (0-
59), секунды (0-59). Определить конструкторы, функции-члены
установки времени, функции получения часа, минуты и секунды,
а также две функции печати: печать по шаблону: "16 часов 18
минут 3 секунды" и "4 p.m. 18 минут 3 секунды". Функции
установки полей класса должны проверять корректность
задаваемых параметров.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на double, количество строк и столбцов и переменную -
20
код ошибки. Определить конструктор без параметров,
конструктор с одним параметром – квадратная матрица и
конструктор с двумя параметрами – прямоугольная матрица и др.
Определить методы доступа: возвращение и определение
значения элемента (i,j). Определить функции сложения и
вычитания (матрицы с матрицей), умножение матрицы на
матрицу. Определить умножение матрицы на число. Проверить
работу этого класса. В случае нехватки памяти, несоответствия
размерностей, выхода за пределы используемой памяти
устанавливать код ошибки.
Вариант 3
а) Создать класс Stack - стек. Поля – общее и используемое
количество элементов и указатель для динамического выделения
памяти. Определить конструкторы: по умолчанию, копий и с
параметром, обозначающим необходимое количество элементов.
Функции Push и Pop для занесения и извлечения соответственно.
Функции IsEmpty и IsFull для определения состояния стека.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на float, количество строк и столбцов и переменную -
код ошибки. Определить конструктор без параметров,
конструктор с одним параметром – квадратная матрица и
конструктор с двумя параметрами – прямоугольная матрица и др.
Определить методы доступа: возвращение и определение
значения элемента (i,j). Определить функции сложения и
вычитания (матрицы с матрицей), умножение матрицы на
матрицу. Определить умножение матрицы на число. Проверить
работу этого класса. В случае нехватки памяти, несоответствия
размерностей, выхода за пределы используемой памяти
устанавливать код ошибки.
21
Вариант 4
а) Создать класс File – файл, содержащий информацию о полном
имени файла и ассоциативном приложении (doc – Word, psd –
Photoshop, etc), используя динамическую память, размер, дату и
время создания. Определить все конструкторы, конструктор
приведения типа - параметр обозначающий имя файла.
Определить функции переименования файла, перемещения в
другую папку и изменения ассоциативного приложения.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на long, количество строк и столбцов и переменную -
код ошибки. Определить конструктор без параметров,
конструктор с одним параметром – квадратная матрица и
конструктор с двумя параметрами – прямоугольная матрица и др.
Определить методы доступа: возвращение и определение
значения элемента (i,j). Определить функции сложения и
вычитания (матрицы с матрицей), умножение матрицы на
матрицу. Определить умножение матрицы на число. Проверить
работу этого класса. В случае нехватки памяти, несоответствия
размерностей, выхода за пределы используемой памяти
устанавливать код ошибки.
Вариант 5
а) Создать класс Document – документ, содержащий информацию
о названии, теме, авторе документа используя динамическую
память, количество страниц, дату и время последней редакции.
Определить все конструкторы: конструктор приведения типа -
параметр обозначающий название документа. Определить
функции переназначение темы, изменение даты последней
редакции и др.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на byte, количество строк и столбцов и переменную -
код ошибки. Определить конструктор без параметров,
конструктор с одним параметром – квадратная матрица и
22
конструктор с двумя параметрами – прямоугольная матрица и др.
Определить методы доступа: возвращение и определение
значения элемента (i,j). Определить функции сложения и
вычитания (матрицы с матрицей), умножение матрицы на
матрицу. Определить умножение матрицы на число. Проверить
работу этого класса. В случае нехватки памяти, несоответствия
размерностей, выхода за пределы используемой памяти
устанавливать код ошибки.
Вариант 6
а) Создать класс Image – картинка, содержащий следующую
информацию: имя файла, формат сжатия, размеры изображения,
размер изображения в байтах, компрессия (%). Определить все
конструкторы, конструктор приведения типа - параметр
обозначающий имя файла. Определить функции переназначение
имени файла, формата, размеров и др.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на Complex, количество строк и столбцов и
переменную - код ошибки. Определить конструктор без
параметров, конструктор с одним параметром – квадратная
матрица и конструктор с двумя параметрами – прямоугольная
матрица и др. Определить методы доступа: возвращение и
определение значения элемента (i,j). Определить функции
сложения и вычитания (матрицы с матрицей), умножение
матрицы на матрицу. Определить умножение матрицы на число.
Проверить работу этого класса. В случае нехватки памяти,
несоответствия размерностей, выхода за пределы используемой
памяти устанавливать код ошибки.
Вариант 7
а) Создать класс Queue - очередь. Поля – количество элементов и
указатель для динамического выделения памяти. Определить
конструкторы: по умолчанию, копий и с параметром,
обозначающим необходимое количество элементов. Функции
23
add и get для занесения и извлечения соответственно. Функции
isEmpty и isFull для определения состояния очереди.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на int, количество строк и столбцов и переменную -
код ошибки. Определить конструктор без параметров,
конструктор с одним параметром – квадратная матрица и
конструктор с двумя параметрами – прямоугольная матрица и др.
Определить методы доступа: возвращение и определение
значения элемента (i,j). Определить функции сложения и
вычитания (матрицы с матрицей), умножение матрицы на
матрицу. Определить умножение матрицы на число. Проверить
работу этого класса. В случае нехватки памяти, несоответствия
размерностей, выхода за пределы используемой памяти
устанавливать код ошибки.
Вариант 8
а) Создать класс String – строка, используя динамическую
память. Определить конструкторы: по умолчанию, копий и с
параметром – указателем на строку типа char. Определить
функции присваивания одной строки другой, сравнения, поиска
подстроки, количества символов и др.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на double, количество строк и столбцов и переменную -
код ошибки. Определить конструктор без параметров,
конструктор с одним параметром – квадратная матрица и
конструктор с двумя параметрами – прямоугольная матрица и др.
Определить методы доступа: возвращение и определение
значения элемента (i,j). Определить функции сложения и
вычитания (матрицы с матрицей), умножение матрицы на
матрицу. Определить умножение матрицы на число. Проверить
работу этого класса. В случае нехватки памяти, несоответствия
размерностей, выхода за пределы используемой памяти
устанавливать код ошибки.
24
Вариант 9
а) Создать класс Дисциплина, содержащий информацию о
предмете обучения, преподавателе, количестве часов и о форме
сдачи (экзамен или зачет). Использовать динамическую память
для задания текстовых полей. Определить конструкторы: по
умолчанию, копий и с параметром, обозначающим название
предмета. Определить функции переназначения преподавателя,
количества часов и формы сдачи.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на float, количество строк и столбцов и переменную -
код ошибки. Определить конструктор без параметров,
конструктор с одним параметром – квадратная матрица и
конструктор с двумя параметрами – прямоугольная матрица и др.
Определить методы доступа: возвращение и определение
значения элемента (i,j). Определить функции сложения и
вычитания (матрицы с матрицей), умножение матрицы на
матрицу. Определить умножение матрицы на число. Проверить
работу этого класса. В случае нехватки памяти, несоответствия
размерностей, выхода за пределы используемой памяти
устанавливать код ошибки.
Вариант 10
а) Создать класс Soft – файл, содержащий информацию о полном
имени файла и ассоциативном приложении (doc – Word, psd –
Photoshop, etc), используя динамическую память, размер, дату и
время создания. Определить конструкторы: по умолчанию,
копий и с параметром, обозначающим имя файла. Определить
функции переименования файла, перемещения в другую папку и
изменения ассоциативного приложения.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на long, количество строк и столбцов и переменную -
код ошибки. Определить конструктор без параметров,
конструктор с одним параметром – квадратная матрица и
25
конструктор с двумя параметрами – прямоугольная матрица и др.
Определить методы доступа: возвращение и определение
значения элемента (i,j). Определить функции сложения и
вычитания (матрицы с матрицей), умножение матрицы на
матрицу. Определить умножение матрицы на число. Проверить
работу этого класса. В случае нехватки памяти, несоответствия
размерностей, выхода за пределы используемой памяти
устанавливать код ошибки.
Вариант 11
а) Создать класс Group – группа, содержащий информацию о
коде группы, специальность, количестве студентов,
соответствующий руководитель группы и год обучения.
Использовать динамическую память для задания текстовых
полей. Определить все виды конструкторов. Определить
функции переназначения руководителя и количества студентов.
Определить функцию назначения года обучения таким образом,
что бы можно было только увеличивать значения этого поля и
оно не могло содержать значение более 5.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на byte, количество строк и столбцов и переменную -
код ошибки. Определить конструктор без параметров,
конструктор с одним параметром – квадратная матрица и
конструктор с двумя параметрами – прямоугольная матрица и др.
Определить методы доступа: возвращение и определение
значения элемента (i,j). Определить функции сложения и
вычитания (матрицы с матрицей), умножение матрицы на
матрицу. Определить умножение матрицы на число. Проверить
работу этого класса. В случае нехватки памяти, несоответствия
размерностей, выхода за пределы используемой памяти
устанавливать код ошибки.
26
Вариант 12
а) Создать класс Set – множество целых чисел, используя
динамическую память. Определить конструкторы: по умолчанию
и копий. Определить функции включения нового элемента во
множество, определения принадлежности элемента множеству,
сложения, вычитания и пересечения множеств.
b) Создать класс Matrix-матрица. Данный класс содержит
указатель на Complex, количество строк и столбцов и
переменную - код ошибки. Определить конструктор без
параметров, конструктор с одним параметром – квадратная
матрица и конструктор с двумя параметрами – прямоугольная
матрица и др. Определить методы доступа: возвращение и
определение значения элемента (i,j). Определить функции
сложения и вычитания (матрицы с матрицей), умножение
матрицы на матрицу. Определить умножение матрицы на число.
Проверить работу этого класса. В случае нехватки памяти,
несоответствия размерностей, выхода за пределы используемой
памяти устанавливать код ошибки.
27
ЛАБОРАТОРНАЯ РАБОТА №3
Основные понятия
Мотивация
Когда заходит разговор об операторах, то чаще всего
программисты говорят что, либо не умеют ими пользоваться,
либо никогда их не используют. Причина такого отношения к
операторам состоит в том, что их использование, принося пользу
(запись становится короче), в тоже время усложняют понимание
кода, так как не всегда возможно, либо тяжело отследить какой
оператор используется встроенный или перегруженный.
Особенно эта проблема остро стоит перед начинающими
программистами, однако к этому синтаксису легко привыкнуть,
после нескольких упражнений. Самый же главный вопрос
состоит в том, так уж необходима перегрузка операторов? Ответ
абсолютно однозначен – необходима. Есть случаи, в которых
просто невозможно без них обойтись. Таковым является
оператор присваивания. Конечно, компилятор сам может создать
необходимый код, либо мы можем определить метод, на пример
Assign (Как сделано на Java). Однако, оба эти решения не
идеальны.
Недостаток первого состоит в том, что в этом случае будет
использовано побитовое копирование, что устраивает нас только
до тех пор, пока в классе не используются указатели:
28
class Book{
char* name;
public:
Book(char n){
name = new char[strlen(n)+1];
strcpy(name,n);
}
~Book(){
delete[] name;
}
void print(){
cout<<name;
}
};
void main(){
Book b(“Stroustrup”), b2(“Lippman”);
b2 = b;
b.print();
b2.print();
}
29
Исходя из всего выше сказанного, можно сделать вывод,
что, по крайней мере, один оператор абсолютно необходим.
Определение и использование
Но что же такое оператор? Оператор это функция с
предопределенным именем и специальным синтаксисом вызова.
Определяется операторы при помощи зарезервированного слова
operator, после которого следует символ операции. В остальном
это обычная функция, имеющая результат и параметры.
Complex operator+(const Complex& r){
return Complex(re+r.re,im+r.im);
}
Типы операторов
Все операторы делятся на две группы: унарные и
бинарные1. Унарными называются операторы имеющие один
единственный оператор. На пример оператор & - взятие адреса, +
+ - инкрементация, ! – отрицание и др. Бинарные имеют два
операнда: + - сложение, * - умножение и др.
О бинарных операторах многого не скажешь, а вот унарные
имеют две формы (правда не все). Например, оператор ++ может
быть записан как i++, а можно и ++i. Как же компилятору
различить какую реализацию вызвать? Для этого было введено
1
На самом деле бывают еще и тернарные операторы, точнее оператор,
так как он один единственный и не перегружаемый, по этому не
вызывающий у нас интерес. Это оператор ?:.
30
правило: постфиксный указатель имеет один дополнительный
параметр целого типа:
Формы перегрузки
Существует две формы перегрузки: как метод класса (с
этим способом мы уже знакомы) и как дружественная функция.
Дружественный оператор определяется по правилам обычным,
для дружественных функций. Встает вполне закономерный
вопрос: а зачем собственно используются обе формы
перегрузки? Неужели недостаточно перегрузки как метод
класса? Зачем оператору быть другом класса? Чтобы ответить на
этот вопрос нужно вспомнить что, например, оператор << всегда
определяется как дружественный. Причина этого состоит в том,
как вызываются методы класса. Практически всегда передается
объект, используя скрытый указатель this. Если нужно еще что-
нибудь передать, то используются обычные параметры. То есть
первый операнд обязательно должен быть представителем
данного класса. В случае оператора << первый операнд типа
ostream а не определяемого нами. Другими словами если нужно
сложить комплексное с целым то это может сделать как
оператор-метод класса, так и друг, а сложить целое и
комплексное – только друг. То есть в данном случае от перемены
мест слагаемых все меняется.
Перечень операторов
Не все операторы могут быть переопределены. Это
связано с синтаксисом языка, перегрузка абсолютно всех
операторов привела бы к слишком сложным правилам их
использования. Нельзя перегружать следующие операторы:
31
Однако можно перегружать некоторые операторы, на
которых и не подумаешь:
Рекомендации
Кроме всего выше сказанного нужно добавить еще
несколько слов о перегрузке операторов:
- нельзя определить оператор для встроенных типов, но они
могут участвовать в операции;
- нельзя определять один и тот же оператор и как метод
класса и как друг класса;
- все операторы должны возвращать результат типа
отличного от void; исключение operator();
- приоритет операторов не меняется;
- operator() может иметь любое количество аргументов, то
есть он не подпадает под обычную классификацию
операторов.
2
Вызов данного оператора похож на вызов обычной глобальной
функции, имя которой совпадает с именем объекта.
32
Контрольные вопросы:
33
Задания
Вариант 1
а) Создать класс целых чисел. Определить операторы "++" и "+",
как методы класса, а "- -" и "-" как дружественные функции.
Операторы должны позволять осуществления операций, как с
переменными данного класса, так и с переменными встроенного
целого.
b) Создать класс Set – множество целых чисел, используя
динамическую память. Определить операторы работы с
множествами: "+" – объединение, "*" – пересечение, "-"
вычитание, как дружественные функции, а "+=" – включение
нового элемента в множество, "==" – сравнения на равенство, и
др. как методы класса. Определить операторы "<<" и ">>". Также
определить функцию определения принадлежности элемента
множеству.
Вариант 2
а) Создать класс 2-D координат. Определить операторы "+" и "-"
как дружественные функции, а операторы присваивания и
сравнения как методы класса. Должны быть возможность
осуществления операций, как между координатами, так и между
координатами и обычными числами.
b) Создать класс Stack – стек, используя динамическую память.
Определить операторы "+" – сложения стеков, "=" –
присваивания, "()" – выдачи нового стека содержащего
последние n элементов - как методы класса. Определить
операторы сравнения "==", "!=", "<", ">", как дружественные
функции. Для реализации последних двух операторов
определить функцию, вычисляющую норму элементов стека.
Определить операторы ввода/вывода в поток. Класс должен быть
полностью функционален, то есть содержать все необходимые
конструкторы и деструктор.
34
Вариант 3
а) Создать класс 3-D координат. Определить операторы "+", "-",
"=" как методы класса, а операторы сравнения как
дружественные функции. Должны быть возможность
осуществления операций, как между координатами, так и между
координатами и обычными числами.
b) Создать класс Queue - очередь, используя динамическую
память. Определить операторы "+" – сложения стеков, "=" –
присваивания как методы класса. Определить операторы
сравнения "==", "!=", "<", ">", как дружественные функции. Для
реализации последних двух операторов определить функцию,
вычисляющую норму элементов очереди. Перегрузить
операторы "<<" и ">>" для ввода/вывода в поток, так и для
вставки/извлечения элементов в/из очереди.
Вариант 4
а) Создать класс Date – дата, содержащая поля: день, месяц, год.
Определить операторы "+" и "-", как методы класса, а "++" и "--"
в обеих формах (префиксная и постфиксная) как дружественные
функции. Оператор "+" должен позволять осуществление
операции только с переменными встроенного int. (x=y+5;).
Должна быть предусмотрена корректная работа с високосными
годами.
b) Создать класс List - очередь. Определить операторы "+" –
сложения списков, "=" – присваивания как методы класса.
Определить операторы сравнения "==", "!=", "<", ">", как
дружественные функции. Перегрузить операторы "<<" и ">>" для
ввода/вывода в поток, так и для вставки/извлечения элементов
в/из очереди. Класс должен быть полностью функционален, то
есть содержать все необходимые конструкторы и деструктор.
Для упрощения работы используйте класс либо структуру
ListItem для представления элементов списка, на которые и
ссылается List.
35
Вариант 5
а) Создать класс действительных чисел. Определить операторы
"++" и "+", как методы класса, а "- -" и "-" как дружественные
функции. Операторы должны позволять осуществления
операций, как с переменными данного класса, так и с
переменными встроенного double.
b) Создать класс Vector – вектор, используя динамическую
память. Определить операторы "+" – поэлементное сложения
векторов, "-" – поэлементное вычитание векторов, "=" –
присваивания, как методы класса. Определить операторы
сравнения "==", "!=", "<", ">", как дружественные функции. Для
реализации последних двух операторов определить функцию,
вычисляющую норму элементов вектора. Перегрузить операторы
"<<" и ">>" для ввода/вывода в поток. Класс должен содержать
все необходимые конструкторы и деструктор.
Вариант 6
а) Создать класс целых чисел большой величины. Определить
операторы "+" и "*", как методы класса, а "-" и "/" как
дружественные функции. Перегрузить операторы инкремента и
декремента в обеих формах (префиксная и постфиксная).
Операторы должны позволять осуществления операций, как с
переменными данного класса, так и с переменными встроенного
long.
b) Создать класс Matrix – матрица, используя динамическую
память. Определить операторы "+" –сложение матриц, "-" –
вычитание матриц, "=" – присваивания, как методы класса.
Определить операторы сравнения "==", "!=", "<", ">", как
дружественные функции. Для реализации последних двух
операторов определить функцию, вычисляющую норму
элементов матрицы. Определить оператор "[]" так, чтобы
обращение [][] к элементам имело смысл. Перегрузить
операторы "<<" и ">>" для ввода/вывода в поток.
36
Вариант 7
а) Создать класс Bool – логические переменные. Определить
операторы "+" – логическое ИЛИ, "*" – логическое И "^" –
ИСКЛЮЧИТЕЛЬНОЕ ИЛИ, как методы класса, а операторы
"==" и "!=" как дружественные функции. Операторы должны
позволять осуществления операций, как с переменными данного
класса, так и с переменными встроенного int. (Если целое число
отлично от нуля, считается что переменная истинна, в противном
случае ложна).
b) Создать класс String – строку, используя динамическую
память. Определить операторы "+" –сложение строк, "=" и "+=" –
присваивания, как методы класса. Определить операторы
сравнения "==", "!=", "<", ">", как дружественные функции.
Операторы должны работать как со String, так и с char*.
Определить оператор "[]" для доступа к каждому символу в
отдельности. Перегрузить операторы ввода/вывода в поток.
Вариант 8
b) Создать класс Stack – стек, используя динамическую память.
Определить операторы "+" – сложения стеков, "=" –
присваивания, "()" – выдачи нового стека содержащего
последние n элементов - как методы класса. Определить
операторы сравнения - "==", "!=", "<", ">", как дружественные
функции. Для реализации последних двух операторов
определить функцию, вычисляющую норму элементов стека.
Определить операторы ввода/вывода в поток.
а) Определить класс Complex – комплексные числа. Определить
все односимвольные операторы как дружественные операторы, а
двухсимвольные как методы класса. Исключение – оператор
присваивания, который может быть только методом класса и
операторы вводы/вывода в поток. Сложение и вычитание должно
производиться как с комплексными числами, так и со
встроенным double.
37
Вариант 9
а) Создать класс Time – время, содержащая поля: часы, минуты,
секунды. Определить операторы "+" и "-", как дружественные
функции, а "++" и "--" в обеих формах (префиксная и
постфиксная) как методы класса. Операторы должны позволять
осуществления операций, как с переменными данного класса, так
и с переменными встроенного int (обозначает секунды).
b) Создать класс Queue - очередь, используя динамическую
память. Определить операторы "+" – сложения стеков, "=" –
присваивания как методы класса. Определить операторы
сравнения "==", "!=", "<", ">", как дружественные функции. Для
реализации последних двух операторов определить функцию,
вычисляющую норму элементов очереди. Перегрузить
операторы "<<" и ">>" для ввода/вывода в поток, так и для
вставки/извлечения элементов в/из очереди.
Вариант 10
а) Создать класс Bool – логические переменные. Определить
операторы "+" – логическое ИЛИ, "*" – логическое И "^" –
ИСКЛЮЧИТЕЛЬНОЕ ИЛИ, как дружественные функции, а
операторы "==" и "!=" как методы класса. Операторы должны
позволять осуществления операций, как с переменными данного
класса, так и с переменными встроенного int. (Если целое число
отлично от нуля, считается что переменная истинна, в противном
случае ложна.)
b) Создать класс Set – множество целых чисел, используя
динамическую память. Определить операторы работы с
множествами: "+" – объединение, "*" – пересечение, "-"
вычитание, как методы класса, а "+=" – включение нового
элемента в множество, "==" – сравнения на равенство, и др. как
дружественные функции. Определить операторы "<<" и ">>".
Также определить функцию определения принадлежности
элемента множеству.
38
Вариант 11
а) Создать класс Date – дата, содержащая поля: день, месяц, год.
Определить операторы "+" и "-", как методы класса, а "++" и "--"
в обеих формах (префиксная и постфиксная) как дружественные
функции. Оператор "+" должен позволять осуществление
операции только с переменными встроенного int. (x=y+5;).
Должна быть предусмотрена корректная работа с високосными
годами.
b) Создать класс String – строку, используя динамическую
память. Определить операторы "+" –сложение строк, "=" и "+=" –
присваивания, как дружественные функции. Определить
операторы сравнения "==", "!=", "<", ">", как методы класса.
Операторы должны работать как со String, так и с char*.
Определить оператор "[]" для доступа к каждому символу в
отдельности. Перегрузить операторы "<<" и ">>" для
ввода/вывода в поток.
Вариант 12
а) Создать класс 2-D координат. Определить операторы "+" и "-"
как дружественные функции, а операторы присваивания и
сравнения как методы класса. Должны быть возможность
осуществления операций, как между координатами, так и между
координатами и обычными числами.
b) Создать класс List - очередь. Определить операторы "+" –
сложения списков, "-" – вычитание (как в множестве) как
дружественные функции. Определить операторы сравнения "==",
"!=", "<", ">", как методы класса. Перегрузить операторы "<<" и
">>" для ввода/вывода в поток, так и для вставки/извлечения
элементов в/из очереди. Класс должен быть полностью
функционален, то есть содержать все необходимые
конструкторы и деструктор. Для упрощения работы используйте
класс либо структуру ListItem для представления элементов
списка, на которые и ссылается List.
39
ЛАБОРАТОРНАЯ РАБОТА №4
Основные понятия
Мотивация
Наследование один из трех основных механизмов
объектно-ориентированного наследования. Наследование может
быть изучено с двух точек зрения: разработчика и пользователя
класса.
С точки зрения разработчика наследование означает, что
поведение и свойства производного класса, являются
расширением свойств базового класса. А с точки зрения
пользователя – наследование обозначает существование ряда
частично взаимозаменяемых классов с единым интерфейсом.
(Инженеры ИТ и машиностроения оба, в первую очередь
являются инженерами).
Преимущества наследования:
- уменьшение объема кода и его повторное
использование;
- уменьшение количества ошибок и себестоимости;
- единый интерфейс и подставляемость;
- увеличение скорости разработки;
40
Издержки наследования: единственной издержкой
наследования можно назвать некоторое падение скорости
выполнения кода. Все же заботы об эффективности не должны
входить в противоречие с преимуществами, так как потери, на
самом деле, не существенны, так как частично их можно обойти
использованием подставляемых функций.
class Animal{
int NofLegs;
public:
void Say(){ cout<<”!!!”; }
};
class Dog: public Animal{ // наследование
...
};
void main(){
Dog d;
d.Say();
}
41
Принцип подстановки
Кроме всего выше сказанного, наследование предполагает,
что объект производного класса может быть использован вместо
объекта базового:
void main(){
Animal *ptr = new Dog;
}
Формы наследования
В отношении наследования, С++ очень богатый язык, так
как существуют пять разных форм наследования. На этой
лабораторной работе мы исследуем три из них, те что
называются простыми.
- открытое;
- закрытое;
- защищенное;
Разные формы наследования используются, для того чтобы
изменить статус доступа для переменных членов класса.
Например, при использовании закрытого наследования, все
доступные (открытые и защищенные) переменные базового
класса становятся закрытыми в производном. А при защищенном
наследовании – защищенными. Закрытые переменные базового
класса при любой форме наследования становятся
недоступными. Кроме того формы наследования, отличаются
тем, что открытое наследование создает подтип данных, то есть
соответствует принципу подстановки, а защищенное и открытое
– нет.
42
Композиция
Композиция это еще один механизм, связанный с ООП,
обозначающий отношение между объектами, тогда как
наследование это отношение между классами.
Наследование реализует отношение быть "is a". Собака
является млекопитающим, а млекопитающее – животным.
Композиция же реализует отношение содержать "has a".
Автомобиль содержит двигатель и колеса.
Определение композиции
На самом деле композиция используется очень широко, так
как и встроенные переменные имеют тип и используются при
определении класса. Однако при использовании переменных
встроенного типа вопросов не возникает, чего не скажешь о
пользовательских классах. Само по себе определение не сложно,
сложности состоят в использовании конструкторов.
class Car{
Engine e;
};
Инициализаторы
Как известно закрытые переменные базового класса
становятся недоступными, следовательно, их невозможно
инициализировать в конструкторе производного и, кроме того,
это противоречит принципу повторного использования кода.
Выход один – вызов конструктора базового класса. Так оно и
происходит, но только для конструкторов по умолчанию и
копий, сгенерированного компилятором. Все остальные должны
быть вызваны вручную. Та же проблема и при композиции, так
же может быть использован только конструктор по умолчанию и
копий3. Для решения этих проблем используются
3
Причина того, что компилятор создает код вызова только для этих
конструкторов, состоит в том, что компилятор знает, как их вызывать и
что им передавать в параметрах.
43
инициализаторы – позволяющие вызывать любые конструкторы
и производить любую инициализацию.
class Engine{
int power;
public:
Engine(int p){power=p;}
};
class Transport{
...
public:
Transport(char*);
};
class Car:public Transport{ // наследование
Engine e; // композиция
public:
Car():Transport(“automobile”),e(10){}
};
Что выбрать
Так как и наследование и композиция являются
инструментами реутилизации кода, встает вполне осмысленный
вопрос: когда использовать наследование и когда композицию.
По этому поводу существует много разных рекомендаций,
однако, легче всего запомнить следующее правило: нужно
поставить себе вопрос: новый класс является ли подтипом (Dog
is an Animal), если мы получили утвердительный ответ значит
должно быть использовано наследование; в противном случае
другой вопрос: не является ли новый класс контейнером (Car has
a door) – в этом случае композиция.
44
К сожалению, для некоторых случаев данная стратегия
бесполезна. К примеру, класс множество можно создать на базе
класса список, но какой механизм использовать. Можно
наследование, а можно композицию. В этом случае правила
сложнее. Нужно задать себе несколько вопросов:
- будут ли объекты нового класса подставляться в
место старого?
- нужно ли переопределить какую-нибудь
виртуальную функцию?
- обрабатывает ли новый тип те же сообщения что и
старый?
- Не является ли базовый класс абстрактным?
Если ответы положительны, используйте наследование4.
Контрольные вопросы:
4
Часто для замены композиции наследованием используется закрытое
наследование – создающее подкласс, а не подтип.
45
Задания
Вариант 1
а) Создать иерархию классов игра – спортивная игра – волейбол.
Определить конструкторы, деструктор, оператор присваивания и
другие необходимые функции.
b) Создать класс колесо, имеющий радиус. Определить
конструкторы и методы доступа. Создать класс автомобиль,
имеющий колеса и строку обозначающую фирму-производителя.
Создать производный класс грузовой автомобиль, отличающийся
грузоподъемностью. Определить конструкторы, деструктор и
другие необходимые функции.
Вариант 2
а) Создать класс студент, у которого есть имя, специальность,
год обучения и средний балл. Определить функции установки,
изменения данных, сравнения. Для задания текстовых полей
использовать оператор new. Определить конструкторы,
деструктор и другие необходимые функции. Создать
производный класс студент-дипломник, для которого
определена тема дипломной работы. Так же, необходимо
определить все необходимые функции.
b) Создать класс комната, имеющая площадь. Определить
конструкторы и методы доступа. Создать класс однокомнатных
квартир, содержащий комнату и кухню (ее площадь), этаж
(комната содержится в классе однокомнатная квартира).
Определить конструкторы, методы доступа. Определить
производный класс однокомнатные квартиры с адресом
(дополнительное поле - адрес). Определить конструкторы,
деструктор и вывод в поток.
46
Вариант 3
а) Создать класс мебель, содержащий информацию о цене, стиле
и области применения (офисная, кухонная и др. мебель). Для
задания текстовых полей использовать динамическую память.
Определить производные классы: стол и стул. Определить
конструкторы, деструктор, оператор присваивания и другие
необходимые функции.
b) Создать класс гараж, имеющий площадь. Определить
конструкторы и методы доступа. Создать класс дом, содержащий
комнаты, кухню (ее площадь) и гараж. Определить производный
класс дача (дополнительный параметр – количество земли).
Определить конструкторы, деструктор и вывод в поток.
Вариант 4
а) Создать иерархию классов человек и сотрудник, занимающий
соответствующий пост и получающий соответствующую
зарплату. Переопределить вывод в поток и ввод из потока,
конструктор копирования, оператор присваивания через
соответствующие функции базового класса.
b) Создать класс карта, имеющая ранг и масть. Карту можно
перевернуть и открыть. Создать класс - колода карт,
содержащий карты. Создать два производных класса от колоды
карт, в одном карты могут извлекаться только по порядку, в
другом – случайным образом.
Вариант 5
а) Создать класс жидкость, имеющий название (указатель на
строку), плотность. Определить конструкторы, деструктор и
операторы вывода в поток. Создать производный класс -
спиртные напитки, имеющий крепость. Определить функции
переназначения плотности и крепости.
47
b) Создать класс кнопка, содержащая некий текст. Определить
конструкторы и метод доступа. Создать класс окно, содержащий
кнопку и координаты окна. Определить конструкторы и
деструктор. Определить производный класс окно с кнопкой и
сообщением. Определить конструкторы, деструкторы и
операторы вывода в поток.
Вариант 6
а) Создать класс человек, имеющий имя (указатель на строку),
возраст, вес. Определить конструкторы, деструктор и оператор
присваивания. Создать производный класс - совершеннолетний,
имеющий номер паспорта. Определить конструкторы по
умолчанию и с разным числом параметров, деструкторы,
операторы вывода в поток. Определить функции переназначения
возраста и номера паспорта.
b) Определить класс корова состоящее из следующих полей:
идентификационный номер – должно быть гарантировано
уникально (для чего использовать статический счетчик), средний
надой, возраст, кличку и породу. Для задания текстовых полей
использовать оператор new. Определить класс стадо, состоящее
из неограниченного количества коров. Определить методы
вставки, удаление, определения среднего надоя по стаду и общий
надой, и другие необходимые функции.
Вариант 7
а) Создать иерархию классов здание, административное здание
и жилое здание. Переопределить вывод в поток и ввод из потока,
конструктор копирования, оператор присваивания через
соответствующие функции базового класса.
b) Создать класс студент, у которого есть имя, специальность,
год обучения и средний балл. Определить функции установки,
изменения данных, сравнения. Для задания текстовых полей
использовать оператор new. Определить конструкторы,
деструктор и другие функции. Создать класс группа содержащий
48
студентов (неограниченное количество). Определить методы
вставки, удаление студентов, определения среднего балла по
группе, конструкторы, деструкторы и др. необходимые функции.
Вариант 8
а) Создать иерархию классов: учебное заведение – абстрактный
базовый класс и дошкольное у.з., среднее у.з. и высшее у.з. –
производные классы. Переопределить ввод/вывод в поток,
конструктор копирования, оператор присваивания через
соответствующие функции базового класса.
b) Создать класс двигатель, у которого есть фирма-
производитель, тип, мощность. Определить функции установки,
изменения параметров двигателя. Создать иерархию классов:
корабль – базовый класс и пассажирский пароход –
производный. Корабль имеет двигатель, грузоподъемность,
водоизмещение, название, порт приписки. Для задания
текстовых полей использовать оператор new.
Вариант 9
а) Создать иерархию классов пресса - газета, журнал и
электронное издание. Определить поля: название издания,
тираж, подписной индекс, периодичность издания. Для задания
текстовых полей использовать оператор new. Переопределить
вывод в поток и ввод из потока, конструктор копирования,
оператор присваивания через соответствующие функции
базового класса.
b) Определить класс Processor - процессор, содержащий
информацию о названии процессора, его частоте, используемой
технологии производства и размере внутренней памяти.
Определить класс Computer - компьютер, состоящий из
процессора и других компонентов. Для задания текстовых полей
использовать оператор new. Определить конструкторы, функции
вывода в поток и другие необходимые функции.
49
Вариант 10
а) Создать иерархию классов транспорт – воздушный
транспорт – вертолет. Переопределить вывод в поток и ввод из
потока, конструктор копирования, оператор присваивания через
соответствующие функции базового класса.
b) Определить класс химический элемент, содержащий
информацию о названии элемента его химических свойствах.
Определить класс медикаменты, содержащий разное количество
хим. элементов и в разном количестве. Определить
конструкторы, функции вывода в поток и другие необходимые
функции.
Вариант 11
а) Создать иерархию классов датчик – абстрактный базовый
класс и датчики температуры, влажности и скорости ветра. Для
каждого класса определить свои единицы измерения и способ
снятия данных о значениях состояния окружающей среды.
Переопределить вывод в поток и ввод из потока, конструктор
копирования, оператор присваивания через соответствующие
функции базового класса.
b) Создать класс Устройство сбора информации о погоде
состоящее из датчиков по заданию а. Для снятия значений
создать класс генератор значений для каждого датчика.
Продемонстрировать работу устройства.
Вариант 12
а) Создать иерархию классов Шахматная фигура – абстрактный
класс, содержащий поле – цвет. Создать производные классы все
фигуры, содержащие свое название и координаты позиции на
доске. Для задания текстовых полей использовать оператор new.
Переопределить вывод в поток и ввод из потока, конструктор
копирования, оператор присваивания через соответствующие
функции базового класса.
50
b) Создать класс Шахматы, состоящее из набора фигур из
задания а, и шахматной доски – двумерный массив 8 на 8.
Должна быть возможность удаления фигур с поля. Определить
конструктор динамически создающий фигуры и задающий их
позиции в шахматной нотации (Е2). Определить конструктор
копий и оператор присваивания.
51
ЛАБОРАТОРНАЯ РАБОТА №5
Основные понятия
Мотивация
Множественное наследование, представляет собой
наследование от двух и более классов. Для того, что бы понять,
зачем нам необходимо множественное наследование нужно
вспомнить, что одиночное наследование не решает всех проблем,
так как иногда вынуждает выбирать между двумя подходящими
базовыми классами.
Интересно высказывание Буча относительно этого
механизма: «Множественное наследование - как парашют: как
правило, он не нужен, но, когда вдруг он понадобится, будет
жаль, если его не окажется под рукой»5.
Таким образом, данный механизм абсолютно необходим.
Однако, он используется далеко не во всех языках, но реализован
в С++. Приведем пример:
Необходимо описать класс Окно с кнопкой и заголовком,
при чем классы Окно, Окно с кнопкой, Окно с заголовком уже
созданы и представляют собой следующую иерархию.
5
Буч Г. «Объектно-ориентированный анализ и проектирование с
примерами приложений на С++». Москва «Бином» 1998 г.
52
Window
Button Titled
Window Window
Button
Titled
Window
Определение
Множественное наследование определяется следующим
образом:
class Student{
public:
int mark;
...
};
class Worker{
public:
int salary;
};
class Practicant: public Student, public Worker{
};
void PutMark(Student& s, int mark){
s.mark = mark;
}
void PutSalary(Worker& w, int salary){
w. salary = salary;
}
void main(){
Practicant p;
PutMark(p,5);
PutSalary(p,200);
}
class A{
public:
int x;
};
class B{
public:
int x;
};
};
void main(){
C c;
c.x = 10;
}
55
совпадать, но имена классов нет6. То есть, для указания какая
переменная используется нужно указать класс, от которого
наследована переменная:
c.A::x = 10;
c.B::x = 5;
class A{
public:
int x;
A(int x){this->x=x;}
};
class B: virtual public A{
public:
B(int x):A(x){}
};
class C: virtual public A{
public:
C(int x):A(x){}
};
class D: public B, public C{
6
В соответствии с новым стандартом могут существовать классы с
одинаковыми именами, но в разных пространствах имен.
56
public:
D(int x):A(x),B(x),C(x){}
}
Контрольные вопросы:
57
Задания
Вариант 1
a) Создать иерархии наследования: студент, сотрудник -
практикант.
b) Создать иерархии наследования: человек - студент,
сотрудник - практикант.
Вариант 2
a) Создать иерархии наследования: млекопитающее,
пресмыкающееся – утконос.
b) Создать иерархии наследования: животное - млекопитающее,
пресмыкающееся – утконос.
Вариант 3
a) Создать иерархии наследования: телевизор, цифровое
устройство – монитор.
b) Создать иерархии наследования: электронное устройство -
телевизор, цифровое устройство – монитор.
Вариант 4
a) Создать иерархии наследования: авторучка, карандаш –
авторучка с грифелем.
b) Создать иерархии наследования: письменные
принадлежности - авторучка, карандаш – авторучка с
грифелем.
58
Вариант 5
a) Создать иерархии наследования: катер, мотоцикл – водный
мотоцикл.
b) Создать иерархии наследования: транспорт - катер, мотоцикл
– водный мотоцикл.
Вариант 6
a) Создать иерархии наследования: диван, кровать – диван-
кровать.
b) Создать иерархии наследования: мебель - диван, кровать –
диван-кровать.
Вариант 7
a) Создать иерархии наследования: воздушный транспорт,
пассажирский транспорт - лайнер Boing 747
b) Создать иерархии наследования: транспорт - воздушный
транспорт, пассажирский транспорт - лайнер Boing 747
Вариант 8
a) Создать иерархии наследования: удочка, телескоп –
телескопическая удочка.
b) Создать иерархии наследования: предмет - удочка, телескоп –
телескопическая удочка.
Вариант 9
a) Создать иерархии наследования: бумага, собственность –
акции.
b) Создать иерархии наследования: предмет - бумага,
собственность – акции.
Вариант 10
a) Создать иерархии наследования: легковой автомобиль,
грузовой автомобиль – внедорожник.
b) Создать иерархии наследования: автомобиль - легковой
автомобиль, грузовой автомобиль – внедорожник.
59
Вариант 11
a) Создать иерархии наследования: книга, тетрадь – записная
книжки.
b) Создать иерархии наследования: бумага - книга, тетрадь –
записная книжки.
Вариант 12
a) Создать иерархии наследования: самолет, корабль - водный
самолет.
b) Создать иерархии наследования: транспорт - самолет,
корабль - водный самолет.
60
ЛАБОРАТОРНАЯ РАБОТА №6
Тема: Полиморфизм. Виртуальные функции
Цели работы:
исследование полиморфизма;
изучение принципов позднего связывания;
изучение виртуальных функций;
полиморфизм ad-hoc;
реализация виртуальных функций;
изучение абстрактных классов.
Основные понятия
Слово полиморфизм греческого происхождения и
приблизительно переводится как "много форм" (poly — много,
morphos — форма). Слово morphos имеет отношение к
греческому богу сна Морфею (Morphus), который мог являться
спящим людям в любой форме, в какой только пожелает.
В жизни полиморфные виды — это те, которые
характеризуются наличием различных форм или характеристик.
В химии полиморфные соединения могут кристаллизоваться, по
крайней мере, в двух различных формах (например, углерод
имеет две кристаллические формы — графита и алмаза). С
другой стороны, инженер ИТ воспринимается в первую очередь
как человек, а потом как инженер (принцип подстановки).
В языках программирования полиморфный объект — это
сущность (переменная, аргумент функции), хранящая, во время
выполнения программы, значения различных типов.
Полиморфные функции — это те функции, которые имеют
полиморфные аргументы.
В С++ полиморфизм — естественное следствие:
отношения "быть экземпляром";
механизма пересылки сообщений;
наследования;
принципа подстановки.
61
Одно из важнейших достоинств объектно-
ориентированного подхода состоит в возможности
комбинирования этих средств. В результате получается богатый
набор технических приемов совместного и многократного
использования кода.
Полиморфная переменная многолика: она содержит
значения, относящиеся к различным типам данных.
Полиморфные переменные реализуют принцип подстановки.
Другими словами, хотя для такой переменной имеется
ожидаемый тип данных, фактический тип может быть подтипом
ожидаемого типа. (Нужно вспомнить понятие подтипа и
подкласса). В C++ полиморфные переменные существуют только
как указатели и ссылки.
62
Позднее связывание
Под поздним связыванием нужно понимать механизм
позволяющий определять динамический тип во время
выполнения программы, а не во время компиляции. Похожий
механизм это дескрипторы файлов, так как файлы открываются
во время выполнения программы, а не во время компиляции.
Данный механизм – основа полиморфизма, так как реализуют
виртуальные функции.
Виртуальные функции
Позднее связывание решает проблему, однако, оно не имеет
непосредственного представления в языке. По этому, для
указания его необходимости используются виртуальные
функции, которые записываются с использованием
зарезервированного слова virtual. Виртуальные функции
отличаются от обычных только способом вызова. Однако их
использование имеет смысл лишь при работе с указателями либо
ссылками.
Приведем пример:
#include<iostream.h>
class Animal{
public:
void Say(){ cout<<"!!!\n";}
};
class Dog: public Animal{
public:
void Say(){ cout<<"GAV\n";}
};
class Cat: public Animal{
public:
void Say(){ cout<<"MIAU\n";}
};
void FunSay(Animal a){
a.Say();
}
void main(){
Animal a;
63
Dog d;
Cat c;
FunSay(a);
FunSay(d);
FunSay(c);
}
Полиморфизм ad-hoc
Приводящий в замешательство аспект переопределения
методов в языке C++ — это разница между переопределением
виртуального и невиртуального методов.
Еще большее замешательство возникает, если программист
пытается переопределить виртуальную функцию в подклассе, но
при этом указывает (возможно, по ошибке) другой тип
аргументов. Например, родительский класс содержит описание:
virtual void display (char *, int);
Абстрактные классы
Отложенный метод (иногда называемый абстрактным
методом, а в C++ — чисто виртуальным методом) может
рассматриваться как обобщение переопределения. В обоих
случаях поведение родительского класса изменяется для
потомка. Для отложенного метода, однако, поведение просто не
определено. Любая полезная деятельность задается в дочернем
классе.
class Shape {
public:
...
virtual void draw() = 0;
...
};
65
Контрольные вопросы:
66
Задания
Вариант 1
Создать абстрактный базовый класс Worker с виртуальной
функцией начисления зарплаты. Создать производные классы
StateWorker, HourlyWorker и CommissionWorker, в которых
данная функция переопределена. В функции main определить
массив указателей на абстрактный класс, которым
присваиваются адреса объектов производных классов.
Вариант 2
Создать абстрактный базовый класс Figure с виртуальной
функцией - площадь. Создать производные классы Square, Circle,
Triangle, Trapeze в которых данная функция переопределена. В
функции main определить массив указателей на абстрактный
класс, которым присваиваются адреса различных объектов.
Площадь трапеции: S=(a+b)h/2.
Вариант 3
Создать абстрактный базовый класс прогрессия с виртуальной
функцией - сумма прогрессии. Создать производные классы:
арифметическая прогрессия и геометрическая прогрессия.
Каждый класс имеет два поля типа double. Первое - первый член
прогрессии, второе (double) - постоянная разность (для
арифметической) и постоянное отношение (для геометрической).
Определить функцию вычисления суммы, где параметром
является количество элементов прогрессии.
Арифметическая прогрессия aj=a0+jd, j=0,1,2,…
Сумма арифметической прогрессии: sn=(n+1)(a0+an)/2
Геометрическая прогрессия: aj=a0rj, j=0,1,2,…
Сумма геометрической прогрессии: sn=(a0-anr)/(1-r)
67
Вариант 4
Создать абстрактный класс Mammal – млекопитающие с
виртуальной функцией - описание. Определить производные
классы - Animal и Human. Для животных определить
производные классы Dog - собака и Cow – корова, в которых
функция переопределяется.
Вариант 5
Создать абстрактный базовый класс Lines с виртуальной
функцией f(x). Создать производные классы StraightLine, Ellipse,
hyperbola в которых данная функция переопределена. В функции
main определить массив указателей на абстрактный класс,
которым присваиваются адреса различных объектов. Уравнение
прямой: y=ax+b , эллипса: x2/a2+y2/b2=1, гиперболы: x2/a2-y2/b2=1
Вариант 6
Создать абстрактный базовый класс Figure с виртуальной
функцией - периметр. Создать производные классы Rectangle,
Circle, Triangle, Rhomb в которых данная функция
переопределена. В функции main определить массив указателей
на абстрактный класс, которым присваиваются адреса различных
объектов.
Вариант 7
Создать абстрактный базовый класс Container с виртуальными
функциями вставки и извлечения. Создать производные классы
Stack и Queue, в которых данные функция определены. В
функции main определить массив указателей на абстрактный
класс, которым присваиваются адреса объектов производных
классов.
68
Вариант 8
Создать абстрактный базовый класс Figure с виртуальной
функцией - площадь поверхности. Создать производные классы
параллелепипед, тетраэдр, шар в которых данная функция
переопределена.
Площадь поверхности параллелепипеда: S=6xy.
Площадь поверхности шара: S=4 r2.
Площадь поверхности тетраэдра: S=a2 3
Вариант 9
Создать абстрактный базовый класс Number с виртуальной
функцией - норма. Создать производные классы Complex, Vector
из 10 элементов, Matrix 2 на 2, в которых данная функция
переопределена. В функции main определить массив указателей
на абстрактный класс, которым присваиваются адреса различных
объектов.
Вариант 10
Создать абстрактный базовый класс Учебное заведение с
виртуальной функцией - описания. Создать производные классы
дошкольное у.з., среднее у.з. и высшее у.з. в которых данная
функция переопределена. В функции main определить массив
указателей на абстрактный класс, которым присваиваются
адреса различных объектов.
Вариант 11
Создать абстрактный базовый класс уравнение с виртуальной
функцией - корни уравнения. Создать производные классы
линейное уравнение и квадратное уравнение, в которых данная
функция переопределена.
69
Вариант 12
Создать абстрактный базовый класс Figure с виртуальной
функцией - объем. Создать производные классы параллелепипед,
пирамида, тетраэдр и шар, в которых данная функция
переопределена. В функции main определить массив указателей
на абстрактный класс, которым присваиваются адреса различных
объектов.
Объем параллелепипеда - V=xyz (x,y,z – стороны).
Объем пирамиды: V=xyh (x,y, - стороны, h - высота).
Объем тетраэдра: V= a3 2/12.
Объем шара: V=4 r3/3.
70
ЛАБОРАТОРНАЯ РАБОТА №7
Тема: Шаблоны
Цели работы:
изучение необходимости шаблонов;
изучение правил определения и использования шаблонов;
изучение специализации шаблонов;
изучение потенциальных проблем решаемых при помощи
шаблонов;
Основные понятия
Мотивация
Шаблоны один из самых мощных конструкций языка С++,
но в тоже время, один из менее изученных и редко
используемых. Причина этого кроется в его относительной
сложности и необычном синтаксисе.
Итак, шаблоны представляют собой механизм
позволяющий записывать алгоритм, не привязанный к
определенному типу. Чаще всего шаблоны используются для
создания контейнеров и абстрактных алгоритмов. Контейнеры
это объекты, содержащие другие объекты или данные, чаще
всего неопределенного количества, такие как массивы, стеки,
очереди, ассоциативные списки и др. Под абстрактными
алгоритмами необходимо понимать хорошо изученные способы
обработки данных, как сортировка, поиск и др., записанные без
указания типа данных.
Шаблонами бывают классы и функции. Шаблоны пришли
на смену макросов, так как последние очень часто приводят к
трудноуловимым ошибкам, потому что компилятор не
проверяет, да и не имеет возможности проверить их на
синтаксические ошибки.
Программист, записывая шаблон, создает заготовку,
которая, в последствии, используется уже с указанными типами
71
данных. То есть, на базе шаблона компилятор создает
нормальные функции.
Если шаблон используется с несколькими разными типами
данных, компилятор создает необходимый код для каждого типа
в отдельности. Другими словами, шаблоны не уменьшают
откомпилированный модуль, скорее даже наоборот, но
значительно уменьшает исходный код, что способствует,
уменьшению количества ошибок, упрощает внесение изменений
в код и упрощает восприятие программы в целом, так как
уменьшается количество создаваемых типов и функций.
Определение
Шаблон определяется при помощи зарезервированного
слова template:
Использование
7
В соответствии с новым стандартом также может быть использовано ЗС
“typename“ вместо “class”.
72
Функции используются практически также как и обычные
функции.
void main(){
int masi[10];
float masf[20];
cout<<searchmax(masi,10);
cout<<searchmax(masf,20);
}
void main(){
Stack<int> sti;
Stack<float> stf;
}
Специализация
Иногда нас не устраивает работа шаблона для
определенного типа данных. Приведем пример:
class One{
};
template <class T>
class Two: public One{
};
template <class T>
class Three: public Two<T>{
};
class Four: public Three<int>{
};
template <class T>
class Five: public T{
};
Контрольные вопросы:
76
Задания
Вариант 1
а) Создать шаблонную функцию, меняющую порядок элементов
следующим образом: первая половина списка смещается в конец,
а вторая в начало. На пример: 1 2 3 4 5 6 - 4 5 6 1 2 3. Функция
должна работать с массивом любой длины. Если количество
элементов нечетное, то средний элемент обрабатывать не надо.
b) Создать параметризированный класс Stack. Класс должен
содержать конструкторы, деструктор, а также функции push, pop,
empty, full и операторы ввода/вывода. Для выделения памяти
использовать оператор new.
Вариант 2
а) Создать шаблонную функцию, меняющую порядок элементов
попарно. На пример: 1 2 3 4 5 6 - 2 1 4 3 6 5. Функция должна
работать с массивом любой длины. Если количество элементов
нечетное, то последний элемент обрабатывать не надо.
b) Создать параметризированный класс Vector. Класс должен
содержать конструкторы, деструктор, функции getLength,
операторы [], +, - и операторы ввода/вывода. Для выделения
памяти использовать оператор new.
Вариант 3
а) Создать шаблонную функцию, подсчитывающую количество
повторений заданного параметра в списке. На пример: список -
0 2 3 4 3 6, параметр - 3, результат - 2. Функция должна работать
с массивом любой длины.
b) Создать параметризированные классы List и ListItem. Классы
должны содержать конструкторы, деструкторы, функции add, in,
remove, getLength, операторы [] и ввода/вывода.
77
Вариант 4
а) Создать шаблонную функцию поиска по заданному ключу.
Функция возвращает позицию первого подходящего элемента.
На пример: список - 0 2 3 4 3 6, параметр - 2, результат - 1. В
случае отсутствия подходящего элемента вернуть код ошибки.
Функция должна работать с массивом любой длины.
b) Создать параметризированный класс Queue - очередь. Класс
должен содержать конструкторы, деструктор, функции add, in,
get, getLength, операторы [] и ввода/вывода.
Вариант 5
а) Создать шаблонную функцию поиска второго по величине
элемента списка. На пример: список - 0 2 3 4 3 6, результат - 4.
Функция должна работать с массивом любой длины.
b) Создать параметризированный класс Set - множество. Класс
должны содержать конструкторы, деструктор, функции add, in,
remove, getLength, операторы “+” - объединение, “*” -
пересечение, “-” - разность и операторы ввода/вывода.
Вариант 6
а) Создать шаблонную функцию сортировки по возрастанию
пузырьковым методом. Функция должна работать с массивом
любой длины.
b) Создать параметризированный класс Map – ассоциативный
список, который содержит поля ключ и значение. Одному ключу
соответствует одно значение. Класс должен содержать
конструкторы, деструктор, функции add, removeByKey, getLength,
getByKey, getByValue, операторы [] и ввода/вывода.
78
Вариант 7
а) Создать шаблонную функцию, изменяющую попарно
элементы массива следующим образом: первый элемент будет
равняться сумме пары, а второй разности пары.
На пример: список - 0 2 3 4 3 6, результат 2 –2 7 –1 9 –3.
b) Создать параметризированный класс Matrix – матрица. Класс
должен содержать конструкторы, деструктор, функции getRows,
getCols, операторы [], +, -, * и ввода/вывода.
Вариант 8
а) Создать шаблонную функцию, меняющую порядок элементов
на обратный.
На пример: 1 2 3 4 5 6 - 6 5 4 3 2 1. Функция должна работать
с массивом любой длины.
b) Создать параметризированный класс Tree – бинарное дерево.
Класс должен содержать конструкторы, деструктор, функции
add, in, функции обхода дерева и операторы ввода/вывода.
Вариант 9
а) Создать шаблонную функцию, подсчитывающую количество
элементов, значение которых больше заданного параметра. На
пример: список - 0 2 3 4 3 6, параметр - 5, результат - 1. Функция
должна работать с массивом любой длины.
b) Создать параметризированный класс Stack. Класс должен
содержать конструкторы, деструктор, а также функции push, pop,
empty и операторы ввода/вывода. Для выделения памяти
использовать оператор new, по n элементов.
79
Вариант 10
а) Создать шаблонную функцию сортировки элементов массива
по убыванию методом вставки. Функция должна работать с
массивом любой длины.
b) Создать параметризированный класс MultiMap – мульти-
ассоциативный список, который содержит поля ключ и список
значений. То есть, одному ключу может соответствовать
несколько значений. Класс должен содержать конструкторы,
деструктор, функции add, removeByKey, getLength, getByKey,
getByValue, операторы [] и ввода/вывода.
Вариант 11
а) Создать шаблонную функцию, подсчитывающую количество
элементов, значение которых меньше заданного параметра. На
пример: список - 0 2 6 4 3 3, параметр - 3, результат - 2. Функция
должна работать с массивом любой длины.
b) Создать параметризированный класс PriorityQueue –
приоритетная очередь. Каждый элемент очереди имеет
определенный приоритет и при извлечении выбирается элемент с
наибольшим приоритетом, а элементы с одинаковыми
приоритетами - по времени добавления. Класс должен
содержать конструкторы, деструктор, функции add, in, get,
getLength, операторы [] и ввода/вывода.
Вариант 12
а) Создать шаблонную функцию поиска второго минимального
по величине элемента списка. На пример: список - 0 2 3 4 3 6,
результат - 2. Функция должна работать с массивом любой
длины.
b) Создать параметризированный класс Matrix – матрица. Класс
должен содержать конструкторы, деструктор, функции getRows,
getCols, операторы [], +=, -=, *= и ввода/вывода.
80
СПИСОК ЛИТЕРАТУРЫ
81
СОДЕРЖАНИЕ
82
ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ С++
Методические указания к лабораторным работам
83
84