- •Содержание
- •ВВЕДЕНИЕ
- •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. Полосы прокрутки
- •Литература
3.5. Указатель this
Как отмечалось выше, если некоторая функция является компонентой объекта, то при вызове этой функции к компонентам-данным этого объекта можно обращаться по имени (опуская имя объекта). Например, пусть имеется объявление двух объектов:
my_class ob1,ob2;
Вызовы компонент-функций имеют вид ob1.fun_1();
ob2.fun_2();
Пусть в обеих функциях содержится инструкция Р cout << str;
При объявлении двух объектов создаются две компонентыИ-данные str. Возникает вопрос, откуда каждая из двух функций узнает, с какой из компонент ей работать (точнее, где она расположена). Ответ состоит в Уследующем. В па- мяти для каждого располагаемого объекта создается скрытыйГуказатель, ад- ресующий начало выделенной под объект области памяти. Получить значение этого указателя в компонентах-функциях можно посредством ключевого слова this. Для любой функции, принадлежащей классу my class, указатель this неявно
объявлен так: |
ая |
|
my_class *const this; |
к |
Б |
Таким образом, при объявлении объе тов ob1 и ob2 создаются два this- указателя на эти объекты. Следовательно, люб функция, являющаяся компо-
нентой некоторого объекта, при вызо получает this-указатель на этот объект. |
|||
И приведенная выше инструкция в функции воспринимается как |
|||
cout << this->str; |
|
|
ве |
Однако эта форма записи избы очна. С другой стороны, явное использо- |
|||
вание указателя this эффект в при решении некоторых задач. |
|||
|
и |
|
|
Рассмотрим пример |
сп льзтвания this-указателя на примере упорядочи- |
||
л |
но |
|
|
вания чисел в массиве. |
|
|
|
#include<iostream> |
|
|
|
using namespace std; |
|
|
|
и |
|
|
|
#include<stdio.h> |
|
|
|
Б |
|
|
|
class m clб |
|
|
|
{ int a[3]; |
|
|
|
public: |
|
|
|
m cl srt(); |
|
// функция упорядочивания информации в массиве |
|
m_cl *inpt(); |
|
// функция ввода чисел в массив |
|
void out(); |
|
// вывод информации о результате сортировки |
|
}; |
|
|
|
m_cl m_cl::srt() |
|
// функция сортировки |
{for(int i=0;i<2;i++) for(int j=i;j<3;j++)
36
|
if (a[i]>a[j]) {a[i]=a[i]+a[j]; a[j]=a[i]-a[j]; a[i]=a[i]-a[j];} |
|||||||
|
return *this; |
|
// возврат содержимого объекта, на который |
|||||
|
} |
|
|
|
// указывает указатель this |
|||
|
m_cl * m_cl::inpt() |
// функция ввода |
|
|||||
|
{ for(int i=0;i<3;i++) |
|
|
|
|
|||
|
cin >> a[i]; |
|
|
|
|
|
||
|
return this; |
|
// возврат скрытого указателя this |
|||||
|
} |
|
|
|
// (адреса начала объекта) |
|||
|
void m_cl::out() |
|
|
|
|
|
||
|
{ cout << endl; |
|
|
|
|
Р |
||
|
for(int i=0;i<3;i++) |
|
|
|
||||
|
cout << a[i] << ' '; |
|
|
|
||||
|
} |
|
|
|
|
|
|
И |
|
main() |
|
|
|
|
|
|
|
|
{ m_cl o1,o2; |
|
// описание двух объектов класса m_cl |
|||||
|
o1.inpt()->srt().out(); |
|
|
|
У |
|||
|
// вызов компонент-функций первого объекта |
|||||||
|
o2.inpt()->srt().out(); |
// вызов компонентГ-функций второго объекта |
||||||
|
return 1; |
|
|
|
|
Б |
|
|
|
} |
|
|
|
|
|
|
|
|
Вызов компонент-функций для |
|
ждого из созданных объектов осущест- |
|||||
вляется |
|
|
|
а |
|
|||
|
o1.inpt()->srt().out; |
|
||||||
|
к |
|
|
|||||
|
|
|
|
|
|
|
||
|
Приведенная инструкция инт рпретируется следующим образом: |
|||||||
|
сначала вызывае ся функцияеinpt для ввода информации в массив данных |
|||||||
объекта о1; |
|
|
|
|
|
|
|
|
|
функция inpt в звращ |
адрес памяти, где расположен объект о1; |
||||||
|
далее вызываетсяаетфункция сортировки информации в массиве, возвра- |
|||||||
щающая соде |
|
м |
объекта о1; |
|
|
|
||
|
|
|
ое |
|
|
|
|
|
|
пос е этого вызывается функция вывода информации. |
|||||||
|
|
ржи |
|
|
|
|
|
|
|
Ниже приведен текст еще одной программы, явно использующей указа- |
|||||||
тель this. лВ ней выполняется добавление строки-компоненты одного объекта к |
||||||||
строке-компоненте другого. |
|
|
|
|
||||
|
б |
|
|
|
|
|
|
|
|
#include<iostream.h> |
|
|
|
|
|||
и |
|
|
|
|
|
|
|
|
Б |
#include<string.h> |
|
|
|
|
|||
class B; |
|
|
// предварительное объявление класса В |
|||||
class A |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ char *s; |
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
A(char *s) |
// конструктор с параметром char* |
||||||
|
{ this->s=new char[strlen(s)+1]; |
// память под строку-компоненту |
||||||
|
strcpy(this->s,s);// копирование строки-аргумента в строку-компоненту |
|||||||
|
|
|
|
|
|
|
|
37 |
}
~A(){delete [] this->s;} void pos_str(char *);
}; |
|
class B |
|
{ char *ss; |
|
public: |
|
B(char *ss) |
// конструктор с параметром char* |
{char *dd; БГУИР int i,ii;
dd=new char[strlen(this->s)+strlen(s)+2];амя//п ть для перезаписи 2 строк strcpy(dd,this->s); // перезапись в dd строки объекта a1 dd[strlen(this->s)]=' '; // удаление ’\0’к
ii=strlen(this->s);
for(i=0;*(s+i);i++) // дозаписьев dd строки объекта b1
|
delete [] this->s; |
|
|
// удаление с роки объекта a1 |
|||
|
this->s=dd; |
|
|
о |
|||
|
|
|
|
|
// перенаправление указателя на строку dd |
||
|
|
|
и |
т |
|||
} |
cout << this->s << endl; |
|
|||||
|
|
|
|
|
|
|
|
void main(void) |
|
|
|
|
|
||
|
б |
|
|
|
|
|
|
{ A a1("aa bcc dd ee"); |
|
|
|
||||
|
B b1("bd"); |
л |
|
|
|
|
|
} |
a1.pos str(b1.f_this()); |
|
|
|
|||
|
|
|
|
|
|
|
|
В результатеи |
выполнения программы получим |
||||||
aa bcc dd ee bd |
|
|
|
|
|
||
БОтметим основные правила использования this-указателей: |
-каждому объявляемому объекту соответствует свой скрытый this- указатель;
-this-указатель может быть использован только для нестатической функции;
-this указывает на начало своего объекта в памяти;
-this не надо дополнительно объявлять;
38
-this передается как скрытый аргумент во все нестатические (не имеющие спецификатора static) компоненты-функции своего объекта;
-указатель this − локальная переменная и недоступна за пределами объекта;
-обращаться к скрытому указателю можно this или *this.
3.6. Встроенные функции (спецификатор inline)
В ряде случаев в качестве компонент класса используются достаточно простые функции. Вызов функции означает переход к памяти, в которой распо- ложен выполняемый код функции. Команда перехода занимает память и требу- ет времени на ее выполнение, что иногда существенно превышает затраты па-
мяти на хранение кода самой функции. Для таких функций целесообразно по- |
|||||||
местить код функции вместо выполнения перехода к функцииР. В этом случае |
|||||||
|
|
|
|
|
|
|
У |
при выполнении функции (обращении к ней) выполняется сразу ее код. Функ- |
|||||||
|
|
|
|
|
|
Г |
|
ции с такими свойствами являются встроенными. Иначе Иговоря, если описание |
|||||||
компоненты функции включается в класс, то такая функция называется встро- |
|||||||
енной. Например: |
|
|
|
Б |
|
||
|
|
|
|
|
|||
class stroka |
|
|
а |
|
|||
{ char str[100]; |
|
|
|
||||
|
public: |
|
|
|
|||
|
|
…….. |
|
е |
|
||
|
int size() |
|
|
||||
|
{ for(int i=0; *(str+i); i++);к |
|
|
||||
|
} |
return i; |
т |
|
|
|
|
|
|
|
|
|
|
||
}; |
о |
|
|
|
|
||
|
|
|
|
|
|||
|
ци |
|
|
|
|
|
|
В описанн м примере функция size() – встроенная. Если функция, объяв- |
ленная в классе, а писанная за его пределами, должна быть встроенной, то она |
|
|
л |
описывается со спе фикатором inline: |
|
|
class stroka |
|
{ char str[100]; |
и |
|
Б |
public: |
б…….. |
|
|
int size(); |
};
}
Спецификация inline может быть проигнорирована компилятором, по-
скольку иногда введение встроенных функций оказывается невозможным или нежелательным.
39