- •Содержание
- •ВВЕДЕНИЕ
- •1.ОБЪЕКТНО-ОРИЕНТИРОВАННЫЙ ПОДХОД
- •2. ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ
- •2.1. Абстрактные типы данных
- •2.2. Базовые принципы объектно-ориентированного программирования
- •2.3. Основные достоинства языка С++
- •2.4. Особенности языка С++
- •2.4.1. Ключевые слова
- •2.4.2. Константы и переменные
- •2.4.3. Операции
- •2.4.4. Типы данных
- •2.4.5. Передача аргументов функции по умолчанию
- •2.5.1. Объект cin
- •2.5.2. Объект cout
- •2.5.3. Манипуляторы
- •3.1. Объекты
- •3.2. Понятие класса
- •3.3. Конструктор копирования
- •3.4. Конструктор explicit
- •3.5. Указатель this
- •3.6. Встроенные функции (спецификатор inline)
- •3.7. Организация внешнего доступа к локальным компонентам класса (спецификатор friend)
- •3.8. Вложенные классы
- •3.9. Static-члены (данные) класса
- •3.10. Компоненты-функции static и const
- •3.11. Proxi-классы
- •3.12. Ссылки
- •3.12.1. Параметры ссылки
- •3.12.2. Независимые ссылки
- •3.13. Пространства имен
- •3.13.3. Ключевое слово using как объявление
- •3.13.4. Псевдоним пространства имен
- •3.14. Практические приемы ограничения числа объектов класса
- •4. НАСЛЕДОВАНИЕ
- •4.1.1. Конструкторы и деструкторы при наследовании
- •4.2. Виртуальные функции
- •4.3. Абстрактные классы
- •4.4. Виртуальные деструкторы
- •4.6. Виртуальное наследование
- •5.2. Перегрузка операторов
- •5.2.2. Перегрузка унарного оператора
- •5.2.3. Дружественная функция operator
- •5.2.4. Особенности перегрузки операции =
- •5.2.5. Перегрузка оператора []
- •5.2.6. Перегрузка оператора ()
- •5.2.7. Перегрузка оператора ->
- •5.2.8. Перегрузка операторов new и delete
- •5.3. Преобразование типа
- •5.3.1. Явные преобразования типов
- •6. ШАБЛОНЫ
- •6.1. Параметризированные классы
- •6.2. Передача в шаблон класса дополнительных параметров
- •6.3. Шаблоны функций
- •6.4. Совместное использование шаблонов и наследования
- •6.5. Шаблоны класса и friend-функции
- •6.6. Некоторые примеры использования шаблона класса
- •6.6.1. Реализация smart-указателя
- •6.6.2. Задание значений параметров класса по умолчанию
- •7.2. Состояние потока
- •7.3. Строковые потоки
- •7.4. Организация работы с файлами
- •7.5. Организация файла последовательного доступа
- •7.6. Создание файла произвольного доступа
- •7.7. Основные функции классов ios, istream, ostream
- •8. ИСКЛЮЧЕНИЯ В С++
- •8.2. Перенаправление исключительных ситуаций
- •8.3. Исключительная ситуация, генерируемая оператором new
- •8.6. Спецификации исключительных ситуаций
- •8.7. Задание собственного неожиданного обработчика
- •9. СТАНДАРТНАЯ БИБЛИОТЕКА ШАБЛОНОВ (STL)
- •9.3. Категории итераторов
- •9.4. Операции с итераторами
- •9.5. Контейнеры последовательностей
- •9.5.2. Контейнер последовательностей list
- •9.5.3. Контейнер последовательностей deque
- •9.6. Ассоциативные контейнеры
- •9.6.1. Ассоциативный контейнер multiset
- •9.6.2. Ассоциативный контейнер set
- •9.6.3. Ассоциативный контейнер multimap
- •9.7.1. Адаптер stack
- •9.7.2. Адаптер queue
- •9.7.3. Адаптер priority_queue
- •9.8. Алгоритмы
- •9.8.1. Алгоритмы сортировки sort, partial_sort, sort_heap
- •9.8.2. Алгоритмы поиска find, find_if, find_end, binary_search
- •9.8.3. Алгоритмы fill, fill_n, generate и generate_n
- •9.8.4. Алгоритмы equal, mismatch и lexicographical_compare
- •9.8.6. Алгоритмы работы с множествами
- •9.8.7. Алгоритмы swap, iter_swap и swap_ranges
- •9.8.8. Алгоритмы copy, copy_backward, merge, unique и reverse
- •10. ПРИМЕРЫ РЕАЛИЗАЦИИ КОНТЕЙНЕРНЫХ КЛАССОВ
- •10.1. Связанные списки
- •10.1.1. Реализация односвязного списка
- •10.2. Реализация бинарного дерева
- •11. ПРОГРАММИРОВАНИЕ ДЛЯ WINDOWS
- •11.1. Система, управляемая сообщениями
- •11.2. Управление графическим выводом
- •11.3. Контекст устройства
- •11.3.1. Экран
- •11.3.2. Принтер
- •11.3.3. Объект в памяти
- •11.3.4. Информационный контекст
- •11.4. Архитектура, управляемая событиями
- •11.5. Исходный текст программы
- •11.7. Некоторые новые типы данных
- •11.8. Венгерская нотация
- •11.9. Точка входа программы
- •11.11. Создание окна
- •11.12. Цикл обработки сообщений
- •11.13. Оконная процедура
- •11.14. Обработка сообщений
- •11.15. Обработка сообщений функцией DefWindowProc
- •11.16. Синхронные и асинхронные сообщения
- •11.17. Еще один метод получения описателя контекста устройства
- •11.19. Полосы прокрутки
- •Литература
a.a_3(); B b; b.b_3();
Cc; c.c_3();
Dd; d.a_3();
//d.b_3(); // b_3 cannot access public member declared in class 'B'
//d.c_3(); // c_3 cannot access public member declared in class 'C'
Ee;
ыдущего пункта приводит к формированию объекта av и вызова конструктора
avt производного класса и конструктора book б зового класса (предыдущая |
|
программа): |
а |
|
к |
e.d_3(); |
|
Р |
e.e_1(); |
|
|
return 0; |
|
|
} |
|
И |
4.1.1. Конструкторы и деструкторы при наследовании |
||
Инструкция avt av("книга |
1",123," автор 1") в примереУпрограммы пред- |
|
|
Г |
|
|
Б |
|
void avt::avt(char *s1,int i,char *s2) : book(s1,i)
няется инициализация компонент-данных naz и kl), затем конструктор произ- водного класса avt (инициализация компон нты fm). Поскольку базовый класс
При этом вначале вызывается конструего тор б зового класса book (выпол-
ничего не знает про производные от н |
классы, его инициализация (вызов его |
|
о |
|
|
конструктора) производится перед инициализацией (активизацией конструкто- |
||
ра) производного класса. |
|
|
и |
|
производного класса вызывается |
В противоположность эт мутруктордес |
перед вызовом деструктора баз вого класса. Это объясняется тем, что уничто- жение объекта азового к асса влечет за собой уничтожение и объекта произ-
водного класса, с едовате ьно, деструктор производного класса должен выпол- |
|||
няться перед деструкторомл |
базового класса. |
||
|
Ниже |
ведена программа вычисления суммы двух налогов, в которой ис- |
|
|
|
б |
|
пользована следующая форма записи конструктора базового и производного клас- |
|||
сов. |
при |
|
|
|
имя конструктора(тип переменной_1 имя_переменной_1,…, |
||
|
Б |
тип переменной_n имя_переменной_n) : |
|
|
|
|
|
|
имя_конструктора_базового_класса(имя_переменной_1,…, имя_переменной_k), |
||
|
компонент_данное_1(имя_переменной_m),…, |
||
|
компонент_данное_n(имя_переменной_n); |
||
|
#include "iostream" |
|
|
|
using namespace std; |
// базовый класс |
|
|
class A |
|
pr2(prc2). Аналогично конструктор В считывает из стека 2 double значения prc1
{ |
|
protected:double pr1,pr2; |
// protected для видимости pr в классе B |
||||||||
public: |
|
|
|
|
|
|
|
|
|
||
|
|
A(double prc1,double prc2): pr1(prc1),pr2(prc2) {}; |
|
|
|||||||
}; |
|
void a_prnt(){cout << "% налога = " << pr1 << " и " << pr2 << endl;} |
|||||||||
|
|
|
|
|
|
// производный класс |
|
||||
class B : public A |
|
|
|||||||||
{ |
|
int sm; |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
||
|
|
B(double prc1,double prc2,int sum): A(prc1,prc2),sm(sum) {}; |
|||||||||
|
|
void b_prnt() |
|
|
|
|
|
|
|||
|
|
{ cout << " налоги на сумму = " << sm << endl; |
|
|
|||||||
|
|
cout << "первый = " << pr1 <<"\n втрой = " << pr2 << endl; |
|||||||||
|
|
} |
|
|
|
|
|
|
|
|
Р |
}; |
|
double rashet() {return pr1*sm/100+pr2*sm/100;} |
И |
||||||||
|
main() |
|
|
|
|
|
|
||||
int |
|
|
|
|
|
|
У |
|
|||
{ A aa(9,5.3); |
|
|
|
|
|
||||||
|
// описание объекта аа (базового класса) и инициа- |
||||||||||
|
|
|
|
|
|
// лизация его компонентГс использованием |
|||||
|
|
|
|
|
|
// конструкт |
|
А() |
|
|
|
|
B bb(7.5,5,25000); // описание объектаБbb (производного класса) |
||||||||||
|
|
|
|
|
|
// и иници лиз ция его компонент (вызов конструк- |
|||||
|
|
|
|
|
|
// тора B() и |
онструктора А() (первым)) |
||||
aa.a_prnt(); |
|
|
ора |
|
|
|
|||||
|
|
к |
|
|
|
|
|||||
bb.b_prnt(); |
|
|
|
|
|
|
|||||
cout << "Сумма налогае= " << bb.rashet() << endl; |
|
|
|||||||||
return 0; |
|
|
|
|
|
|
|
|
|||
} |
|
|
|
|
|
|
|
|
|
|
|
В приведенн м примеретиспользованы функции-конструкторы следующе- |
|||||||||||
го вида: |
|
|
|
о |
|
|
|
|
|
|
|
public: A(double prc1,double prc2): pr1(prc1),pr2(prc2) {}; |
|
||||||||||
|
|
|
и |
|
|
|
|
|
|
||
public: B(double prc1,double prc2,int sum): A(prc1,prc2),sm(sum) {}; |
|||||||||||
Конструкторл |
А считывает из стека 2 double значения prc1 и prc2, которые |
||||||||||
далее |
|
спользуются для инициализации компонент класса А pr1(prc1), |
|||||||||
б |
|
|
|
|
|
|
|
|
|
||
и |
|
|
|
|
|
|
|
|
|
|
и prc2 и одно значение int, после чего вызывается конструктор класса |
|
A(prc1,prc2), затем выполняется инициализация компоненты sm класса В. |
|
Б |
Производный класс может служить базовым классом для создания сле- |
дующего производного класса. При этом, как отмечалось выше, конструкторы выполняются в порядке наследования, а деструкторы − в обратном порядке. Ес- ли при наследовании переопределена хотя бы одна перегруженная функция, то все остальные варианты этой функции будут скрыты. Если необходимо, чтобы они оставались доступными в производном классе, все их надо переопределить. Если в производном классе создается функция с тем же именем, типом возвра-
71
щаемого значения и сигнатурой, как и у функции-компоненты базового класса, но с новой реализацией, то эта функция считается переопределенной. Под сиг- натурой понимают имя функции со списком параметров, заданных в ее прото- типе, а также слово const. Типы возвращаемых значений могут различаться.
Ниже приведен текст еще одной программы, в которой также использует- ся наследование. В программе выполняется преобразование арифметического выражения из обычной (инфиксной) формы в форму польской записи. Для это- го используется стек, в который заносятся арифметические операции. Алгоритм
преобразования выражения здесь не рассматривается. |
|
|
|
Р |
||||||||||||||
#include<iostream> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
И |
||||||
using namespace std; |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
#include<stdlib.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
class st |
|
|
|
|
|
|
// класс «элемент стека операций» |
|
||||||||||
{ public : |
|
|
|
|
|
|
|
|
|
|
|
|
Г |
|
|
|||
|
char c; |
|
|
|
|
|
|
|
|
|
|
|
Б |
У |
|
|||
|
st *next; |
|
|
|
|
|
|
|
|
|
|
|
|
|||||
public: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st(){} |
|
|
// |
конструктор |
|
|
а |
|
|
|
|
||||||
|
~st(){} |
|
// |
деструктор |
|
|
|
|
|
|
|
|||||||
}; |
|
|
|
к |
|
|
|
|
|
|||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class cl : public st |
|
|
|
|
// класс преобр зования выражения |
|
||||||||||||
{ |
char *a; |
|
|
|
|
|
// |
|
исходная строка (для анализа) |
|
||||||||
|
char outstr[80]; |
|
|
|
т |
|
|
|
|
|
|
|
||||||
|
|
|
|
|
// |
|
выходная строка |
|
|
|
|
|||||||
public : |
|
|
// |
|
|
|
|
|
е |
|
|
|
|
|
|
|||
|
cl() : st() {} |
к с рук ор |
|
|
|
|
|
|
|
|
||||||||
|
~cl(){} |
|
// |
деструк |
р |
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
и |
|
// |
занесение символа в стек |
|
|
|||||||||
}; |
st *push(st *,char); |
|
|
|
|
|
||||||||||||
|
|
л |
он// |
извлечение символа из стека |
|
|
||||||||||||
|
char pop(st **); |
|
|
|
|
|||||||||||||
|
int PRIOR(char); |
|
|
|
// |
|
определение приоритета операции |
|
||||||||||
|
|
б |
|
|
|
|
// |
преобразование в польскую запись |
|
|||||||||
|
char *ANALIZ(char *); |
|
|
|||||||||||||||
|
и |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char * cl::ANALIZ(char *aa) |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
Б |
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
|
|
|
|
{ st *OPERS; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
OPERS=NULL; |
|
|
|
|
// стек операций пуст |
|
|
|
|
|||||||||
int k,p; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a=aa; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
k=p=0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while(a[k]!='\0'&&a[k]!='=') |
|
|
|
// пока не дойдем до символа '=' |
||||||||||||||
{ if(a[k]==')') |
|
|
|
|
|
|
|
// если очередной символ ')' |
|
|||||||||
|
{ while((c=pop(&OPERS))!='(') // считываем из стека в выходную |
|
||||||||||||||||
|
outstr[p++]=c; |
|
|
|
|
|
|
|
// строку все знаки операций до символа |
|||||||||
72 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
// ‘(‘ и удаляем из стека ‘(‘ |
|||
|
|
|
|
|
|
|
|
|
||
|
|
if(a[k]>='a'&&a[k]<='z') |
|
// если символ – буква, то |
||||||
|
|
outstr[p++]=a[k]; |
|
|
// заносим ее в выходную строку |
|||||
|
|
if(a[k]=='(') |
|
|
|
// |
если очередной символ '(' , то |
|||
|
|
OPERS=push(OPERS,'('); |
// |
помещаем его в стек |
||||||
|
|
if(a[k]=='+'||a[k]=='-'||a[k]=='/'||a[k]=='*') |
|
|||||||
|
|
{ |
|
|
|
// если следующий символ – знак операции, то |
||||
|
|
|
while((OPERS!=NULL)&&(PRIOR(c)>=PRIOR(a[k]))) |
|||||||
|
|
|
outstr[p++]=pop(&OPERS); // переписываем в выходную строку все |
|||||||
|
|
|
|
|
|
// |
находящиеся в стеке операции с большим |
|||
|
|
|
|
|
|
// |
или равным приоритетом |
|||
|
|
|
OPERS=push(OPERS,a[k]); // записываем в стек очереднуюРоперацию |
|||||||
|
|
} |
|
|
|
|
|
|
|
У |
|
|
|
|
|
|
|
|
|
Г |
|
|
|
k++; |
|
// переход к следующему символуИвыходной строки |
||||||
|
|
} |
|
|
|
|
|
|
|
|
|
|
while(OPERS!=NULL) |
// после анализа всего выражения |
|||||||
|
|
outstr[p++]=pop(&OPERS); // |
переписываем операции из стека |
|||||||
|
|
outstr[p]='\0'; |
|
|
// |
в выходную строку |
||||
|
} |
return outstr; |
|
|
к |
Б |
|
|||
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
е |
|
|
|
||
|
|
|
|
|
|
|
|
|
||
|
st *cl::push(st *head,char a) |
// фунация записи символа в стек и возврата |
||||||||
|
{ st *PTR; |
|
т |
// у азателя на вершину стека |
||||||
|
|
if(!(PTR=new st)) |
|
|
|
|
|
|||
|
} |
{ cout << "\n нед с а очно памяти для элемента стека"; exit(-1);} |
||||||||
|
|
|
о |
// инициализация элемента стека |
||||||
|
|
|
PTR->c=a; |
|
||||||
|
|
|
и |
|
|
|
|
|
|
|
|
|
|
PTR->next=head; |
|
|
|
|
|
||
|
|
|
return PTR; |
|
// PTR – вершина стека |
|
||||
|
|
|
л |
|
|
// функция удаления символа с вершины стека |
||||
|
char cl::pop(st **head) |
|||||||||
|
{ st *PTR; |
|
|
// возвращает символ (с вершины стека) и коррек- |
||||||
и |
|
|
|
// тирует указатель на вершину стека |
||||||
Б |
бchar a; |
|
|
|||||||
|
|
// если стек пуст, то возвращается ‘\0' |
||||||||
|
|
if(!(*head)) return '\0'; |
||||||||
|
|
PTR=*head; |
|
// адрес вершины стека |
|
|||||
|
|
a=PTR->c; |
|
|
// считывается содержимое с вершины стека |
|||||
|
|
*head=PTR->next; // изменяем адрес вершины стека (nex==PTR->next) |
||||||||
|
|
delete PTR; |
|
|
|
|
|
|
return a;
}
int cl::PRIOR(char a) // функция возвращает приоритет операции
{ switch(a)
73