
- •Часть 1
- •Общие сведения Сведения об эумк
- •Методические рекомендации по изучению дисциплины
- •Рабочая учебная программа
- •Учреждение образования
- •«Белорусский государственный университет
- •Информатики и радиоэлектроники»
- •Часть 2 __184__
- •Содержание дисциплины
- •1. Индивидуальные практические занятия, их характеристика
- •2. Контрольные работы, их характеристика
- •3. Курсовой проект, его характеристика
- •4. Литература
- •4.1. Основная
- •4.2. Дополнительная
- •5. Перечень компьютерных программ, наглядных и других пособий, методических указаний и материалов и технических средств обучения
- •Протокол согласования учЕбной программы по изучаемой учебной дисциплине с другими дисциплинами специальности
- •Теоретический раздел Введение
- •1. Основные типы данных
- •1.1. Общие сведения
- •1.2. Данные типа int
- •1.3. Данные типа char
- •1.4. Модификаторы доступа const и volatile
- •1.5. Данные вещественного типа (с плавающей точкой)
- •1.6. Элементарный ввод-вывод
- •1.7. Структура простой программы на языке Си
- •2. Операции и выражения
- •2.1. Выражение и его интерпретация
- •2.2. Основные операции
- •2.2.1. Арифметические операции
- •2.2.2. Побитовые логические операции
- •2.2.3. Операции сдвига
- •2.2.4. Операция присваивания
- •2.2.5. Операция sizeof
- •2.2.6. Преобразование типов в выражениях
- •2.2.7. Операция преобразования типов
- •2.2.8. Приоритеты в языке Си
- •3. Операторы управления вычислительным процессом
- •3.1. Оператор if
- •3.2. Операции отношения
- •3.3. Логические операции
- •3.4. Операция запятая
- •3.5. Операция условия ?:
- •3.6. Оператор безусловного перехода goto
- •3.7. Оператор switch
- •`` ` `3.8. Операторы цикла
- •3.8.1. Оператор for
- •3.8.2. Оператор while
- •3.8.3. Оператор do...While
- •3.9. Оператор break
- •3.10. Оператор continue
- •4. Массивы и указатели
- •4.1. Одномерные массивы и их инициализация
- •4.2. Многомерные массивы и их инициализация
- •4.3. Объявление указателей
- •4.4. Операции над указателями
- •1) Взятие адреса
- •2) Косвенная адресация или разыменование указателя
- •3) Увеличение или уменьшение значения указателя на целое число
- •4) Разность указателей
- •5) Сравнение указателей
- •6) Присваивание указателей друг другу
- •4.6. Связь между указателями и массивами
- •4.7. Динамическое распределение памяти
- •4.8. Массивы указателей
- •5. Функции
- •5.1. Общие сведения
- •5.2. Область видимости переменных
- •5.2.1. Локальные переменные
- •5.2.2. Глобальные переменные
- •5.3. Передача параметров в функцию
- •5.4. Рекурсивные функции
- •5.5. Использование функций в качестве параметров функций
- •5.6. Указатели на функции
- •5.7. Структура программы на Си
- •5.8. Передача параметров в функцию main()
- •6. Строки
- •7. Классы хранения и видимость переменных
- •7.1. Общие сведения
- •7.2. Автоматический класс хранения (auto)
- •7.3. Регистровый класс хранения (register)
- •7.4. Статический класс хранения (static)
- •7.5. Внешний класс хранения (extern)
- •7.6. Заключение
- •8. Структуры, объединения и перечисления
- •8.1. Общие сведения
- •8.2. Инициализация структурных переменных
- •8.3. Вложенные структуры
- •8.4. Указатели на структуры
- •8.5. Массивы структурных переменных
- •8.6. Передача функциям структурных переменных
- •8.7. Оператор typedef
- •8.8. Поля битов в структурах
- •8.9. Объединения
- •8.10. Перечисления
- •9. Динамические структуры данных
- •9.1. Общие сведения
- •9.2. Связные списки
- •9.2.1. Односвязные списки
- •9.2.2. Двусвязные списки
- •9.2.3. Циклические списки
- •9.3. Стеки
- •9.4. Очереди
- •9.5. Деревья
- •9.5.1. Понятие графа
- •9.5.2. Бинарные деревья
- •10. Файлы
- •10.1. Общие сведения
- •10.2. Открытие и закрытие файлов
- •10.3. Функции ввода-вывода для работы с текстовыми файлами
- •10.4. Произвольный доступ к файлу
- •10.5. Функции ввода-вывода для работы с бинарными файлами
- •11. Директивы препроцессора
- •11.1. Основные понятия
- •11.2. Директива #include
- •11.3. Директивы препроцессора #define и #undef
- •11.3.1. Символические константы
- •11.3.2. Макросы с параметрами
- •11.3.3. Директива #undef
- •11.4. Условная компиляция
- •11.5. Директивы # и ##
- •12. Модульное программирование
- •13. Введение в объектно-ориентированное программирование
- •13.1. Постановка задачи
- •13.2. Решение задачи средствами Си
- •13.5. Наследование
- •13.6. Перегрузка
- •13.7. Ссылочный тип
- •Литература
- •Приложение 1. Рекомендации по оформлению текстов программ
- •Тесты к теоретическому разделу Вопросы к разделу 1. Основные типы данных
- •Вопросы к разделу 2. Операции и выражения
- •Вопросы к разделу 3. Операторы управления вычислительным процессом
- •Вопросы к разделу 4. Массивы и указатели
- •Вопросы к разделу 5. Функции
- •Вопросы к разделу 6. Строки
- •Вопросы к разделу 7. Классы хранения и видимость переменных
- •Вопросы к разделу 8. Структуры, объединения и перечисления
- •Вопросы к разделу 9. Динамические структуры данных
- •Вопросы к разделу 10. Файлы
- •Вопросы к разделу 11. Директивы препроцессора
- •Вопросы к разделу 12. Модульное программирование
- •Вопросы к разделу 13. Введение в ооп
- •Правильные ответы на вопросы тестов к теоретическому разделу
- •Вопросы к теоретическому зачету
- •Варианты индивидуальных заданий
- •Контрольная работа №2
- •Варианты индивидуальных заданий
- •Индивидуальные практические работы Указания к выбору варианта индивидуальных практических работ
- •Индивидуальная практическая работа № 1. Массивы и строки
- •Варианты индивидуальных заданий
- •Индивидуальная практическая работа № 2. Динамические структуры данных
- •Варианты индивидуальных заданий
13.5. Наследование
При решении многих задач оказывается, что разные классы имеют множество близких свойств и используют большое количество схожего кода. Примерами таких классов могут служить стек и очередь. Если реализовать эти классы раздельно, то в части реализации списков, на которых они основаны, различий может не быть вовсе. Реализовав список, и наследуя от него стек и очередь можно добиться наиболее простого и изящного решения.
Преобразуем список из примера 13.2 в класс iList. Для этого проделаем все то же, что и в разделе 13.1 со стеком: выделим интерфейс и реализацию, заменим имена конструкторов и деструкторов, уберем из числа формальных параметров ссылки на конкретный объект. В результате список примет такой вид:
class iList
{
public:
iList(); // Конструктор
~iList(); // Деструктор
struct TItem* add_item(int num);
int front_item_value();
void removet_item();
private:
struct TItem* front;
int size;
};
iList::iList() // Конструктор
{
size = 0;
front = 0;
}
iList::~iList() // Деструктор
{
while (size) remove_item();
}
// Остальные функции-члены
В данном примере для простоты подразумевается, что в точке объявления класса доступен, определенный ранее «элемент списка». Теперь структура программы такова:
Подключение заголовочных файлов библиотек
Определение типа «элемент списка»
Определение функций работающих с элементами списка
Класс iList
Класс iStack
В связи с изменениями, произошедшими в реализации списка, придется модифицировать стек. Это можно сделать так:
// Класс iStack (стек чисел_типа_int)
class iStack
{
public:
void push(int a);
int pop();
private:
struct iList list; // Список
};
void iStack::push(int a)
{
list.add_item(a);
}
int iStack::pop()
{
int res = list.front_item_value();
list.remove_item();
return res;
}
Следует отметить, что в данном случае нет необходимости в создании конструктора и деструктора класса iStack, т.к. единственная переменная член (list) имеет конструктор и деструктор по умолчанию (т.е. конструктор и деструктор не требующие передачи им параметров), которые будут вызваны автоматически.
Уже на таком простом примере видно, что создание цепочки базирующихся друг на друге классов имеет большие преимущества по сравнению с созданием набора процедур, реализующих более простые сущности. Однако ООП предлагает еще более широкие возможности.
Недостатком приведенной реализации стека может стать то, что, формально, он никак не связан со списком, хотя представляет с ним практически одно целое. Одним из способов указать компилятору, что данные классы имеют родственную структуру (а конкретней, стек – является развитием идеи списка), и, таким образом, избавиться от программирования тех функций стека, которые уже есть в списке, является применение механизма наследования.
class iStack: public iList
{
public:
void push(int a);
int pop();
};
В данном случае класс iList становится предком для iStack и все его члены (кроме конструктора и деструктора) автоматически становятся членами класса-потомка. Определению, очевидно, подлежат функции-члены push() и pop():
void iStack::push(int a)
{
add_front_item(a);
}
int iStack::pop()
{
int res = get_front_item();
del_front_item();
return res;
}
Как и в предыдущем, в данном примере явно не вызываются конструкторы iList и iStack. Это объясняется тем, что первый имеет конструктор по умолчанию, а второму конструктор вообще не нужен (нет данных подлежащих инициализации или действий, которые нужно произвести перед началом работы с экземпляром класса).
Упрощенно наследованием классов называется порождение одного класса от другого. При этом порождающий класс является предком, отцом, базовым классом для порождаемого класса. И наоборот, порождаемый класс – наследник, сын, производный класс относительно порождающего класса. Возможны разные способы наследования. Простейший из них описывается так:
определение_класса_наследника ::=
“class” имя_потомка “: public” имя_предка
“{” { блок_объявлений } “};”
В результате потомок содержит все члены базового класса но имеет доступ лишь к открытым.