- •Кетков ю.Л.
- •Раздел 5. Системные данные текстового типа 33
- •Раздел 6. Основные синтаксические конструкции языка c 46
- •Раздел 7. Указатели и ссылки 59
- •Раздел 8. Функции и их аргументы 62
- •Раздел 9. Работа с массивами. 74
- •Раздел 10. Пользовательские типы данных. 95
- •Раздел 11. Работа с файлами 104
- •Раздел 12. Библиотеки стандартных и нестандартных функций 118
- •Раздел 15. Классы. Создание новых типов данных 131
- •Раздел 16. Классы как средство создания больших программных комплексов 150
- •Раздел 17. Прерывания, события, обработка исключений 167
- •Введение
- •Раздел 1. Немного истории
- •Раздел 2. Структура программы на языке c
- •Раздел 3. Среда программирования
- •Раздел 4. Системные данные числового типа
- •4.1. Типы числовых данных и их представление в памяти эвм
- •4.1.1. Внутреннее представление целочисленных данных
- •4.1.2. Однобайтовые целочисленные данные
- •4.1.3. Двухбайтовые целочисленные данные
- •4.1.4. Четырехбайтовые целочисленные данные
- •4.1.5. Восьмибайтовые целочисленные данные
- •4.2. Внутреннее представление данных вещественного типа
- •4.3. Внешнее представление числовых констант
- •4.4. Объявление и инициализация числовых переменных
- •4.5. Ввод числовых данных по запросу программы
- •4.5.1. Потоковый ввод данных числового типа
- •4.5.2. Форматный ввод
- •4.6. Вывод числовых результатов
- •4.6.1. Форматный вывод
- •4.6.2. Потоковый вывод
- •4.7. Примеры программ вывода числовых данных
- •4.8. Операции над числовыми данными целого типа
- •4.9. Операции над числовыми данными вещественного типа
- •Раздел 5. Системные данные текстового типа
- •5.1. Символьные данные и их представление в памяти эвм
- •5.2. Строковые данные и их представление в памяти эвм
- •5.3. Ввод текстовых данных во время работы программы
- •5.3.1. Форматный ввод
- •5.3.3. Потоковый ввод
- •5.3.4. Специальные функции ввода текстовых данных
- •5.4. Вывод текстовых данных
- •5.4.1. Форматный вывод
- •5.5.2. Операции над строковыми данными
- •5.6. Управление дисплеем в текстовом режиме
- •Раздел 6. Основные синтаксические конструкции языка c
- •6.1. Заголовок функции и прототип функции
- •6.2. Объявление локальных и внешних данных
- •6.3. Оператор присваивания
- •6.4. Специальные формы оператора присваивания
- •6.5. Условный оператор
- •6.6. Оператор безусловного перехода
- •6.7. Операторы цикла
- •6.8. Дополнительные операторы управления циклом
- •6.9. Оператор выбора (переключатель)
- •6.10. Обращения к функциям
- •6.11. Комментарии в программах
- •Раздел 7. Указатели и ссылки
- •7.1. Объявление указателей
- •7.2. Операции над указателями
- •7.3. Ссылки
- •Раздел 8. Функции и их аргументы
- •8.1. Параметры-значения
- •8.2. Параметры-указатели
- •8.3. Параметры-ссылки
- •8.4. Параметры-константы
- •8.5. Параметры по умолчанию
- •8.6. Функции с переменным количеством аргументов
- •8.7. Локальные, глобальные и статические переменные
- •8.8. Возврат значения функции
- •8.9. Рекурсивные функции
- •8.10. Указатели на функцию и передача их в качестве параметров
- •8.11. "Левые" функции
- •Раздел 9. Работа с массивами.
- •9.1. Объявление и инициализация массивов.
- •9.2. Некоторые приемы обработки числовых массивов
- •9.2. Программирование задач линейной алгебры
- •9.2.1. Работа с векторами
- •9.2.2.Работа с матрицами
- •9.3. Поиск
- •9.3.1. Последовательный поиск
- •9.3.2. Двоичный поиск
- •9.4. Сортировка массивов.
- •9.4.1. Сортировка методом пузырька
- •9.4.2. Сортировка методом отбора
- •9.4.3. Сортировка методом вставки
- •9.4.4. Сортировка методом Шелла
- •9.4.5.Быстрая сортировка
- •9.5. Слияние отсортированных массивов
- •9.6. Динамические массивы.
- •Раздел 10. Пользовательские типы данных.
- •10.1. Структуры
- •10.1.1. Объявление и инициализация структур
- •10.1.2. Структуры – параметры функций
- •10.1.3.Функции, возвращающие структуры
- •10.2. Перечисления
- •10.3. Объединения
- •Раздел 11. Работа с файлами
- •11.1.Файлы в операционной системе
- •11.1. Текстовые (строковые) файлы
- •11.2. Двоичные файлы
- •11.3. Структурированные файлы
- •11.4. Форматные преобразования в оперативной памяти
- •11.5. Файловые процедуры в системе bcb
- •11.5.1. Проверка существования файла
- •11.5.2. Создание нового файла
- •11.5.3. Открытие существующего файла
- •11.5.4. Чтение из открытого файла
- •11.5.5. Запись в открытый файл
- •11.5.6. Перемещение указателя файла
- •11.5.7. Закрытие файла
- •11.5.8. Расчленение полной спецификации файла
- •11.5.9. Удаление файлов и пустых каталогов
- •11.5.10. Создание каталога
- •11.5.11. Переименование файла
- •11.5.12. Изменение расширения
- •11.5.13. Опрос атрибутов файла
- •11.5.14. Установка атрибутов файла
- •11.5.15. Опрос и изменение текущего каталога
- •11.6. Поиск файлов в каталогах
- •Раздел 12. Библиотеки стандартных и нестандартных функций
- •12.2. Организация пользовательских библиотек
- •12.3. Динамически загружаемые библиотеки
- •13.1. Препроцессор и условная компиляция
- •13.2. Компилятор bcc.Exe
- •13.3. Утилита grep.Com поиска в текстовых файлах
- •14.1. Переопределение (перегрузка) функций
- •14.2. Шаблоны функций
- •Раздел 15. Классы. Создание новых типов данных
- •15.1. Школьные дроби на базе структур
- •15.2. Школьные дроби на базе классов
- •15.3. Класс на базе объединения
- •15.4. Новые типы данных на базе перечисления
- •15.5. Встраиваемые функции
- •15.6. Переопределение операций (резюме)
- •15.8. Конструкторы и деструкторы (резюме)
- •Раздел 16. Классы как средство создания больших программных комплексов
- •16.1. Базовый и производный классы
- •16.1.1.Простое наследование
- •16.1.2. Вызов конструкторов и деструкторов при наследовании
- •16.1.3. Динамическое создание и удаление объектов
- •16.1.4. Виртуальные функции
- •16.1.5. Виртуальные деструкторы
- •16.1.6. Чистые виртуальные функции и абстрактные классы
- •16.2. Множественное наследование и виртуальные классы
- •16.3. Объектно-ориентированный подход к созданию графической системы
- •Раздел 17. Прерывания, события, обработка исключений
- •17.1. Аппаратные и программные прерывания
- •17.2. Исключения
Раздел 16. Классы как средство создания больших программных комплексов
До сих пор мы знакомились с возможностями классов как средства создания и обработки новых типов данных. Наряду с этим важнейшим достижением языка C++ имеется другая, не менее важная заслуга классов, – они позволяют строить развивающиеся иерархические структуры программных комплексов. И главным механизмом здесь является наследование – возможность порождать новые классы на базе уже имеющихся с передачей порожденным классам наследства в виде данных и членов-функций родительского класса (или классов, если прямых родителей несколько). Порожденные классы имеют возможность расширять набор данных, полученных по наследству, модифицировать родительские методы и функции, создавать новые данные и новые функции их обработки. Возможность сохранять ранее созданное программное хозяйство, модифицируя его в соответствии с новыми задачами, позволяет с меньшими затратами и с большей надежностью вести разработки больших программных систем. Дополнительный выигрыш в производительности процесса разработки программного обеспечения можно получить за счет использования библиотек классов и шаблонов, активно создаваемых в настоящее время.
16.1. Базовый и производный классы
Когда говорят о классе D, порожденном из класса B, то принято называть родительский класс базовым, а вновь созданный класс – производным. Механизм наследования (inheritance) предусматривает две возможности. В первом случае, который называют простым наследованием, родительский класс один. Во втором случае родителей два или больше, и соответствующий процесс именуют термином множественное наследование. В первую очередь мы познакомимся с механизмом простого наследования.
16.1.1.Простое наследование
Итак, как формально выглядит процедура объявления производного класса D и что он получает в наследство от своего родителя – класса B ?
class D: [virtual][public|private|protected] B
{тело производного класса};
Служебное слово virtual (виртуальный) используется для предотвращения коллизий в случае сложного множественного наследования (по этому поводу см. раздел 16.2). Кроме уровней доступа public (общедоступный) и private (личный) в классах, создаваемых на базе структур (struct) и настоящих классов (class), используется еще один уровень защиты – protected (защищенный). Защищенными данными класса могут пользоваться функции и методы самого класса, производных классов и дружественные функции. При создании производного класса D может быть упомянут один из этих уровней доступа, что повлияет на изменение уровня доступа к унаследованным данным и функциям. По этому поводу в стандарте C++ существует целая таблица:
Таблица 16.1
Уровень доступа в B |
Уровень доступа при объявлении D |
Уровень доступа в D |
|
D=struc |
D=class |
||
public |
опущен |
public |
private |
protected |
опущен |
public |
private |
private |
опущен |
нет доступа |
нет доступа |
public |
public |
public |
public |
protected |
public |
protected |
protected |
private |
public |
нет доступа |
нет доступа |
public |
protected |
protected |
protected |
protected |
protected |
protected |
protected |
private |
protected |
нет доступа |
нет доступа |
public |
private |
private |
private |
protected |
private |
private |
private |
private |
private |
нет доступа |
нет доступа |
В современной практике программирования действует общепринятое правило – родителями и потомками должны быть только настоящие классы. Поэтому о существовании третьей колонки в табл. 16.1 можно сразу забыть.
Чаще всего производный класс конструируют по следующей схеме, которая носит название открытого наследования:
class D: public B {тело производного класса};
Это означает, что общедоступные данные и функции из родительского класса остаются общедоступными и в порожденном классе, защищенные данные и функции из родительского класса остаются защищенными и в порожденном классе, а к приватным компонентам родителя потомок прямого доступа не имеет. И добраться до них он может на равных правах с другими программами только через соответствующий метод, если таковой у родителя был предусмотрен.
Однако приведенное выше утверждение не распространяется на конструкторы и деструкторы. Они не наследуются, но к ним можно обратиться с добавлением принадлежности классу B.
В приведенном ниже примере имеет место открытое наследование производного класса D от своего родителя. Поле данных x родительского класса для потомка закрыто, но методы setb и showb сохраняют в классе D уровень доступа public. Поэтому с объектом типа D к этим методам обращаться можно:
#include <iostream.h>
#include <conio.h>
class B {
int b;
public:
void setb(int n){b=n;}
void showb(){cout<<"in B b="<<b<<endl;}
};
class D: public B {
int d;
public:
void setd(int n){d=n;}
void showd(){cout<<"in D d="<<d<<endl;}
};
void main()
{ D qq; //объявление объекта порожденного класса
qq.setb(1); //доступ к члену базового класса qq.x
qq.showb(); //доступ к члену базового класса
qq.setd(2); //доступ к члену производного класса qq.y
qq.showd(); //доступ к члену производного класса
qq.showb(); //доступ к члену базового класса
getch();
}
//=== Результат работы ===
in B b=1 //qq.x
in D d=2 //qq.y
in B b=1 //qq.x
Обратите внимание на то, что после обращения к методу setd значение поля qq.x не изменилось.
А теперь модифицируем уровень доступа при объявлении производного класса:
class D: private B {
int d;
public:
void setbd(int n,int m)
{ setb(n); //для класса D функция стала private, но она доступна
d=m; }
void showbd()
{ showb(); // для класса D функция стала private, но она доступна
cout<<"in D d="<<d<<endl;}
};
void main()
{ D qq; //объявление объекта порожденного класса
qq.setbd(1,2);
qq.showbd();
getch();
}
Результат работы программы прежний, но в доступе к методам класса B помог производный класс. В последнем примере можно заменить в объявлении класса D уровень доступа на protected – функции setb и showb получат в классе D статус protected, но они по-прежнему будут доступны, и результат работы программы будет прежним.