- •Содержание
- •ВВЕДЕНИЕ
- •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. Полосы прокрутки
- •Литература
cout<<” Значение val класса cls = ”<<obj.get()<<endl;
}
В результате выполнения программы получим: Значение val класса cls = 1
Значение val класса cls = 2
Исходный класс cls содержит один private-компонент val и методы, кото- рые требуется скрыть от клиента, взаимодействующего с main()-функцией. В то же время клиент должен иметь возможность взаимодействовать с классом cls.
для класса cls. Так как в определении класса prox используется только указательР на объект класса cls, то включение заголовочного файла класса cls посредством
Для этого используется класс prox, реализация которого содержит public-
интерфейс, аналогичный интерфейсу класса cls, и единственный private-
компонент – указатель на объект класса cls. Класс prox является proxi-классом
инструкции #include необязательно. Достаточно объявить класс как тип данных |
|||||||
путем предварительного объявления. |
|
|
|
|
И |
||
|
|
|
|
|
|||
Файл реализации cls.cpp включает заголовочный файл cls.h с объявлением |
|||||||
|
|
|
|
|
|
У |
|
класса cls. Файл реализации prox.h класса prox является единственным файлом, |
|||||||
|
|
|
|
|
Г |
|
|
|
|
|
|
|
Б |
|
|
включающим файл реализации cls.cpp, а следовательно, и cls.h. Файл prox.cpp |
|||||||
|
|
|
|
еа |
|
|
|
является доступным клиенту только как скомпилированный объектный код и, |
|||||||
|
|
|
к |
|
|
|
|
следовательно, клиент не может видеть взаимодействия между proxi-классом и |
|||||||
классом cls. |
|
|
|
|
|
|
|
В main()-функцию включается толь о файл р |
лизации prox.cpp, при этом |
||||||
отсутствует указание на существова |
ласса |
cls. Следовательно, private- |
|||||
|
|
та |
|
|
|
|
|
данные класса cls скрыты от клиен . ние |
|
|
|
|
|||
3.12. Ссылки |
ри |
спос ба передачи данных в функцию: по значе- |
|||||
В С(С++) известны т |
|||||||
нию, посредством указателя |
сп льзуя ссылки. |
|
|
|
|||
л |
|
|
|
|
|
|
|
При передаче параметровфункцию они помещаются в стековую память. |
|||||||
б |
|
|
|
|
|
|
|
В отличие от стандартных типов данных (char, int, float и др.) объекты обычно требуют много ольше памяти, при этом стековая память может существенно увеличитьсяи. Для уменьшения объема передаваемой через стек информации в С(С++) спользуются указатели. В языке С++ наряду с использованием меха- низмаБуказателей меется возможность использовать неявные указатели (ссыл- ки). Ссылка, по существу, является не чем иным, как вторым именем некоторо- го объекта.
Формат объявления ссылки имеет вид
тип & имя_ссылки = инициализатор.
Ссылку нельзя объявить без ее инициализации. То есть ссылаться всегда можно на некоторый существующий объект. Можно выделить следующие раз- личия ссылок и указателей. Во-первых, невозможность существования нулевых ссылок подразумевает, что корректность их не требуется проверять. А при ис-
54
пользовании указателя требуется проверять его на ненулевое значение. Во- вторых, указатели могут указывать на различные объекты, а ссылка всегда на один объект, заданный при ее инициализации. Ниже приведен пример исполь- зования ссылки.
#include <iostream> using namespace std; #include <string.h>
class A
{char s[80]; int i;
|
|
|
|
|
|
|
|
|
|
|
|
Р |
|
public : |
|
|
|
|
|
|
|
|
|
И |
|
|
A(char *S,int I):i(I) |
{ strcpy(s,S);} |
|
У |
|
|||||||
|
~A(){} |
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
||
|
void see() |
{cout<<s<<" |
"<<i<<endl;} |
Г |
|
|
||||||
|
}; |
|
|
|
|
|
|
|
|
|
||
|
int main() |
|
|
|
|
|
|
|
|
|||
|
{ A a("aaaaa",3),aa("bbbb",7); |
асса |
|
|
||||||||
|
A &b=a; |
|
|
|
|
|
А инициализирована значением а |
|||||
|
|
// ссылка на объект кл |
||||||||||
|
cout<<"компоненты объе та :"; a.see();Б |
|
|
|
||||||||
|
|
|
|
|
|
|
к |
|
|
|
|
|
|
cout<<"компоненты ссыл и :"; b.see(); |
|
|
|
||||||||
|
|
|
|
|
|
ние |
дрес &b= "<< &b << endl; |
|||||
|
cout <<"адрес a="<<&a << " |
|||||||||||
|
b=aa; |
|
|
// присво |
значений объекта aa ссылке b (и объекту a) |
|||||||
|
|
|
|
|
ты |
|
|
|
|
|
|
|
|
cout<<"компонен |
объ кта :"; a.see(); |
|
|
|
|||||||
|
cout<<"компонен ы ссылки :"; b.see(); |
|
|
|
||||||||
|
int i=4,j=2; |
|
|
|
|
|
|
|
|
|
||
|
int &ii=i; |
|
// ссылка на переменную i типа int |
|
|
|||||||
|
|
и |
|
|
|
|
|
|
|
|
||
|
cout << "значение i= "<<i<<" значение ii= "<<ii<<endl; |
|
||||||||||
|
ii++; |
|
о// увеличение значения переменной i |
|
|
|||||||
|
cout << "значение i= "<<i<<" значение ii= "<<ii<<endl; |
|
||||||||||
|
б |
|
|
// инициализация переменной i значением j |
|
|||||||
|
ii=j; |
|
|
|
||||||||
и |
|
|
|
|
|
|
|
|
|
|
|
|
|
coutл<< "значение i= "<<i<<" значение ii= "<<ii<<endl; |
|
||||||||||
Б |
} |
|
|
|
|
|
|
|
|
|
|
|
В результате выполнения программы получим: |
|
|
||||||||||
|
|
|
||||||||||
|
компоненты объекта : aaaaa |
3 |
|
|
|
|
||||||
|
компоненты ссылки : aaaaa |
3 |
|
|
|
|
||||||
|
адрес a= 0x________ адрес &b= 0х________ |
|
|
|||||||||
|
компоненты объекта : bbbbb |
7 |
|
|
|
|
||||||
|
компоненты ссылки : bbbbb |
7 |
|
|
|
|
||||||
|
значение i= 4 значение ii= 4 |
|
|
|
|
|
||||||
|
значение i= 5 значение ii= 5 |
|
|
|
|
|
||||||
|
значение i= 2 значение ii= 2 |
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
55 |
Из примера следует, что переменная и ссылка на нее имеют один и тот же адрес в памяти. Изменение значения по ссылке приводит к изменению значения переменной и наоборот.
Ссылка может также указывать на константу, в этом случае создается временный объект, инициализируемый значением константы.
const int &j=4; |
// j инициализируется const-значением 4 |
j++; |
// ошибка l-value specifies const object |
int k=j; |
// переменная k инициализируется значением |
|
// временного объекта |
Если тип инициализатора не совпадает с типом ссылки, то могут возник- нуть проблемы с преобразованием данных одного типа к другому, например:
double f=2.5; |
|
|
|
|
|
|
|
|
Р |
|
int &n=(int &)f; |
|
|
|
|
|
|
У |
|||
cout<<”f=”<<f<<” n=”<<n; // результат |
f= 2.5 |
n=2 |
|
|
||||||
|
|
|
|
|
|
|
Г |
|
|
|
Адрес переменной f и ссылки n совпадают, но значения различаютсяИ |
, так |
|||||||||
как структуры данных плавающего и целочисленного типов различны. |
|
|
||||||||
Можно создать ссылку на ссылку, например: |
|
|
|
|
||||||
int k=1; |
|
|
|
|
а |
|
|
|
||
int &n=k; |
// n – ссылка на k (равно k) |
Б |
|
|
|
|||||
n++; |
// |
значение k равно 2 |
|
|
|
|
||||
int &nn=n; |
// |
|
ылок |
(переменную k) |
|
|
||||
nn – ссылка на ссыл у n |
|
|
||||||||
nn++; |
// значение k равно 3 |
|
|
|
|
|
||||
Значения адреса переменной k, сс |
|
|
n и nn совпадают, следовательно, |
|||||||
для ссылки nn не создается временный объ кт. |
|
|
|
|
|
|||||
На применение переменных ссылочногое |
типа накладываются некоторые |
|||||||||
ограничения: |
|
|
|
|
|
|
|
|
|
|
- ссылки не являются указа елями; |
|
|
|
|
|
|
|
|||
|
и |
|
ссылочного типа; |
|
|
|
||||
- можно взять ссылку |
т переменнойт |
|
|
|
||||||
|
л |
|
|
|
|
|
|
|
|
|
- можно создать указательона ссылку; |
|
|
|
|
|
|
||||
- нельзя создать масс |
в ссылок; |
|
|
|
|
|
|
|
|
|
- ссылки на |
итовые поля не допускаются. |
|
|
|
|
|||||
и |
|
|
|
|
|
|
|
|
|
|
3.12.1. Параметры ссылки |
|
|
|
|
|
|
|
|
||
Б |
|
|
|
|
|
|
|
|
|
|
Если требуется предоставить возможность функции изменять значения передаваемых в нее параметров, то в языке С они должны быть объявлены либо глобально, либо работа с ними в функции осуществляется через передаваемые в нее указатели на эти переменные. В С++ аргументы в функцию можно переда- вать также и через ссылку. Для этого при объявлении функции перед парамет- ром ставится знак &.
#include <iostream> using namespace std; void fun1(int,int);
56
void fun2(int &,int &); |
|
|
|
|
|
|
|
|||
int main() |
|
|
|
|
|
|
|
|
|
|
{ int i=1,j=2; |
|
|
|
|
// i и j – локальные параметры |
|||||
|
cout << "\n адрес переменных в main() i = "<<&i<<" |
j = "<<&j; |
||||||||
|
cout << "\n |
i = "<<i<<" |
j = "<<j; |
|
|
|
||||
|
fun1(i,j); |
|
|
|
|
|
|
|
|
|
|
cout << "\n |
значение |
|
i = "<<i<<" |
j = "<<j; |
|
|
|||
|
fun2(i,j); |
|
|
|
|
|
|
|
|
Р |
} |
cout << "\n |
значение |
|
i = "<<i<<" |
j = "<<j; |
|
||||
|
|
|
||||||||
|
|
|
|
|
|
|
|
И |
||
void fun1(int i,int j) |
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|||
{ |
cout << "\n адрес переменных в fun1() i = "<<&i<<" |
j = "<<&j; |
||||||||
|
int a; |
|
|
|
// |
|
|
У |
|
|
|
|
|
|
при вызове fun1 i и j из main() копируются |
||||||
|
a=i; i=j; j=a; |
|
|
// |
в стек в переменные i и j при возврате в main() |
|||||
} |
|
|
|
|
// |
они просто теряются |
|
|
||
void fun2(int &i,int &j) |
|
|
|
|
|
|
|
|||
{ |
cout << "\n адрес переменных в fun2() i Г= "<<&i<<" |
j = "<<&j; |
||||||||
|
int a; |
// |
|
|
|
|
а |
|
|
|
|
здесь используются ссылки на переменные i и j из |
|||||||||
|
a=i; i=j; j=a; |
// |
main() (вторые их Бимена) и таким образом действия |
|||||||
|
|
// |
|
|
к |
|
|
|
||
} |
|
в фун ции производятся с теми же переменными i и j |
||||||||
|
|
|
|
|
|
|
|
|
|
|
В функции fun2 в инстру ции |
|
|
|
|
||||||
|
|
т |
|
|
|
|
|
|
a=i; е
не используется операция *. При объявлении параметра-ссылки компилятор С++ определяет егокак неявный указатель (ссылку) и обрабатывает соответст-
менных, а их адреса, благодаря чему функция может модифицировать значения
вующим образом. При выз ве функции fun2 ей автоматически передаются адре- са переменныхиi j. Таким образом, в функцию передаются не значения пере-
этих переменныхл. Будьте внимательны, при вызове функции fun2 знак & перед переменнымиб i и j говорит о том, что в функцию будут переданы адреса этих переменныхи , а не о том, что используются ссылки на них.
3.12.2. Независимые ссылки
В языке С++ ссылки могут быть использованы не только для реализации
механизма передачи параметров в функцию. Они могут быть объявлены в про- |
|
Бграмме наряду с обычными переменными, например: |
|
#include <iostream> |
|
using namespace std; |
|
int main() |
|
{ int i=1; |
|
int &j=i; |
// j – ссылка (второе имя) переменной i |
|
57 |