- •Определение класса
- •Пример (точка)
- •Оператор вывода (пример)
- •Параметр шаблона по умолчанию (пример)
- •Где перехватывать исключения?
- •Гарантии безопасности исключений
- •Базовые операции
- •Виртуальная функция
- •Использование virtual
- •Массив, как диапазон
- •Контейнер
- •Свойства элемента контейнера
- •Заголовочные файлы
- •Доступ к элементам list
- •Размеры list
- •Доступ к элементам map
- •Очередь с приоритетом
- •Дэк (двусвязная очередь)
- •Матрица (в математике)
- •Атд “матрица”
- •Дерево (доп. Определения)
- •Узел дерева (доп. Определения)
- •“Родственные отношения”
- •“Родственные отношения” (иллюстрация)
- •Баланс в дереве (иллюстрация)
- •Std::less (пример функтора)
- •Std::find_if (пример алгоритма)
- •Функциональные адаптеры
- •Производящая функция
- •Производящие функции для функциональных адаптеров
Виртуальная функция
объявляется виртуальной в базовом классе с помощью ключевого слова virtual
связывается динамически при использовании адреса базового класса
остается виртуальной во всех производных классах (достаточно одного объявления в базовом классе)
07.04.2012 cppNewb.ru 6
Использование virtual
|
virtual |
в |
определениях функций
|
virtual |
в |
объявлениях производных классов
переопределение – повторное определение виртуальной функции в производном классе
07.04.2012 cppNewb.ru 7
Виртуальная функция (пример)
class CMan
{
public:
virtual void writeTxt(ostream& os);
…
};
void
CMan::writeTxt(ostream& os)
…
07.04.2012 cppNewb.ru 8
Расширяемость
универсальный код
взаимодействует только с интерфейсом типа (т.е. базового класса)
возможно добавление новых производных классов, без изменения универсального кода
07.04.2012 cppNewb.ru 9
Поиск тела виртуальной функции
компилятор гарантирует наличие тела для виртуальной функции
если виртуальная функция не переопределяется в классе, то вызывается “ближайшее” в иерархии наследования определение
07.04.2012 cppNewb.ru 10
Расширяемость (пример)
//CStudent : public CMan
//CTutor : public CMan
void
printStat(ostream& os, CMan** pPeople)
{
…
(pPeople + iCur)->writeTxt(os);
…
}
07.04.2012 cppNewb.ru 11
Типичная реализация позднего связывания
таблица виртуальных функций VTABLE для каждого класса, содержащего виртуальные функции
скрытое хранение указателя VPTR на
VTABLE в каждом экземпляре класса
автоматическая генерация кода доступа к функции через VTABLE в точке
вызова полиморфной функции
07.04.2012 cppNewb.ru 12
Размещение в памяти
классы без данных приводятся компилятором к ненулевому размеру за счет вставки фиктивной переменой
каждый экземпляр класса с виртуальными функциями хранит скрытый указатель VPTR (перед данными)
в классах без данных с виртуальными функциями место фиктивной переменной занимает указатель VPTR
07.04.2012 cppNewb.ru 13
Схема хранения VTABLE
объект СMan
таблица виртуальных
функций
CMan::writeTxt
vptr CMan::readTxt
объект СStudent
vptr
CStudent::writeTxt
CStudent::readTxt
объект СTutor
vptr
CTutor::writeTxt
CTutor::readTxt
07.04.2012 cppNewb.ru 14
Инициализация указателя VPTR
виртуальные функции не должны вызываться до инициализации VPTR
инициализация VPTR происходит в конструкторе (в т.ч. умолчательном)
07.04.2012 cppNewb.ru 15
Наследование и VTABLE
при создании экземпляра класса в таблицу заносится адреса определенных в классе виртуальных функций
при добавлении в производном классе новых виртуальных функций таблица расширяется
07.04.2012 cppNewb.ru 16
Повышающее приведение и объекты
повышающее приведение типа применимо только к адресам (ссылкам)
если в точке вызова тип точно известен,
используется раннее связывание
(как типичное поведение компилятора)
07.04.2012 cppNewb.ru 17
Эффективность использования виртуальных функций
минусы
дополнительные инструкции для каждого вызова виртуальной функции
дополнительный код для инициализации
дополнительная память для хранения
плюсы
повышение гибкости программ
повышение эффективности работы программистов
07.04.2012 cppNewb.ru 18
Чисто виртуальная функция
объявление начинается с virtual и заканчивается “= 0”
должна реализовываться в производном классе
пример:
virtual int func() = 0;
07.04.2012 cppNewb.ru 19
Объявление чисто виртуальной функции
резервирует ячейку в таблице виртуальных функций VTABLE
не заносит конкретного указателя на реализацию функции
указывает способ использования класса
07.04.2012 cppNewb.ru 20
Абстрактный класс
содержит нереализованные чисто виртуальные функции
создание экземпляров абстрактных классов запрещено
при наследовании от абстрактного класса все чисто виртуальные функции д.б. реализованы
07.04.2012 cppNewb.ru 21
Абстрактный класс как тип
определяет тип (интерфейс)
используется в качестве базового в иерархии наследования для классов реализующих данный интерфейс
используется в реализации алгоритмов над объектами типа
07.04.2012 cppNewb.ru 22
Использование абстрактных классов
запрещает передачу экземпляров по значению
гарантирует осуществление повышающего приведения типа через указатель или ссылку
07.04.2012 cppNewb.ru 23
Определение чисто виртуальной функции
аналогично обычной функции
класс остается абстрактным
позволяет вызывать общий код в производных классах
07.04.2012 cppNewb.ru 24
Определение чисто виртуальной функции (пример)
class CPrintable
{
public:
virtual void writeTxt(ostream& os) = 0;
};
void CPrintable::writeTxt(ostream& os)
{
// общий код
}
// class CMan : public CTxtIO
07.04.2012 cppNewb.ru 25
Изменение типа возвращаемого
значения
возможно
функция базового класса
возвращает указатель или ссылку на базовый класс
переопределенная функция
может возвращать указатель или ссылку на производный класс
07.04.2012 cppNewb.ru 26
Особенности конструкторов и деструкторов
код инициализации VPTR вставляется в конструктор
механизм виртуального вызова не работает в конструкторах и деструкторах
07.04.2012 cppNewb.ru 27
Виртуальный деструктор
нужен для правильно разрушения объекта производного класса через указатель/ссылку базового класса
деструктор базового класса обязательно д.б. виртуальным
пример:
virtual ~CBase();
07.04.2012 cppNewb.ru 28
Чисто виртуальный деструктор
имеет право быть
должен иметь тело
предотвращает возможность создания экземпляров класса
07.04.2012 cppNewb.ru 29
Однокоренные иерархии
работа с контейнерами
отладочный функционал
протоколирование
сохранение/восстановление данных
07.04.2012 cppNewb.ru 30
Динамический полиморфизм
реализуется через механизмы виртуальных функции и наследования
имя функции сопоставляется с кодом функции на этапе выполнения
07.04.2012 cppNewb.ru 31
Полиморфизм
помогает создавать расширяемые программы
увеличивает возможности повторного использования кода и упрощает сопровождение
механизм реализации и использования абстракций
07.04.2012 cppNewb.ru 32
Интерфейсный класс
содержит только объявления функций
не содержит данных
не содержит определений объявленных функций
все функции д.б. чисто виртуальными
07.04.2012 cppNewb.ru 33
Наследование интерфейса в С++
реализуется через наследование от интерфейсного (абстрактного) класса
наиболее разумный случай
использования множественного наследования
07.04.2012 cppNewb.ru 34
Ассоциативность операторов
правоассоциативные
присваивания
унарные операторы
левоассоциативные
пример:
a = b = c означает a = (b = c) a + b + c означает (a + b) + c
07.04.2012
cppNewb.ru 35
Порядок вычислений
порядок вычислений подвыражений не определен
пример:
c = f(a) + g(b); //< порядок произвольный
int i(1);
v[i] = i++; //< v[1] = 1 или v[1] = 2 или …
07.04.2012
cppNewb.ru 36
Не могут быть переопределены
?:
тернарный условный оператор
sizeof
оператор вычисления размера типа
typeid
оператор получения информации о типе
07.04.2012
cppNewb.ru 37
Не могут быть переопределены
операторы доступа
::
оператор разрешения области видимости
.
оператор выбора члена
.*
оператор выбора члена через указатель на член
07.04.2012
cppNewb.ru 38
Причины ограничения перегрузки
правым операндом является не значение, а имя
основные средства доступа к членам
07.04.2012
cppNewb.ru 39
Рекомендуемые типы
bool
char
int
double
07.04.2012
cppNewb.ru 40
Выбор типа
unsigned - массив битов
signed – все остальное
требуемая точность
ограничения по использованию памяти
Диапазоны арифметических типов
тип |
минимальный диапазон |
char |
[-128,127] или [0, 255] |
unsigned char |
[0, 255] |
signed char |
[-128, 127] |
int |
[-2^15, 2^15 - 1] |
unsigned int |
[0, 2^16] |
double |
10 значащих цифр |
wchar_t |
как unsigned int |
Размеры арифметических типов
1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long)
sizeof(float) <= sizeof(double) <= sizeof(long double)
sizeof(T) == sizeof(signed T) == sizeof(unsigned T)
Неявные преобразования
повышение
bool -> int
enum -> int или long
обеспечение точности
int + long
int + double -> double
усечение
int n(f);
07.04.2012
cppNewb.ru 44
Явные преобразования
static_cast<Тип>(выражение)
преобразование родственных типов
пример:
int roundVal = static_cast<int>(doubleVal);
07.04.2012
cppNewb.ru 45
Явные преобразования
const_cast<Тип>(выражение)
изменение константности
пример:
char* pBeg = const_cast<char*>(p + n);
07.04.2012
cppNewb.ru 46
Явные преобразования
reinterpret_cast<Тип>(выражение)
трактовка битового представления
обычно применяется к указателям
пример:
// void *p
char* pBeg = reinterpret_cast<char*>(p);
07.04.2012
cppNewb.ru 47
Явные преобразования
dynamic_cast<Тип>(выражение)
понижающее приведение
0 – если не из одной иерархии
пример:
// class Child : public Parent
Child* pCh = dynamic_cast<Child*>(pParent);
07.04.2012
cppNewb.ru 48
Преобразования в стиле С
избегать использования
(Тип)выражение или Тип(выражение)
пример:
int roundVal = int(doubleVal + 0.5);
int roundVal = (int)doubleVal;
07.04.2012
cppNewb.ru 49
Объектно-ориентированное
программирование
с использованием C++
Полевой Дмитрий Валерьевич к.т.н., доцент КиК
e-mail: oop.misis@gmail.com
Псевдоним типа (typedef)
typedef OldType NewType;
|
псевдоним |
типа, |
но |
не вводит |
новый тип |
|
|
часто используется
для сокращения кода, в т.ч. за счет подстановки параметров шаблонов
для сокрытия деталей реализации
14.04.2012 cppNewb.ru 2
Псевдоним типа (примеры)
typedef unsigend int size_t;
typedef basic_string<char> string;
14.04.2012 cppNewb.ru 3
Вложенные типы
определяются внутри определения типа (класс, структура)
подчиняются спецификаторам доступа
доступ с помощью оператора разрешения области видимости
в т.ч. для typedef
14.04.2012 cppNewb.ru 4
Вложенные типы (пример)
class Container
{
public:
typedef long SizeType;
...
private:
class Node
{
...
14.04.2012 cppNewb.ru 5
Обобщенное программирование
Остерн М.Г.
Обобщенное программирование и STL. Использование и наращивание стандартной библиотеки шаблонов C++
Александреску А.
Современное проектирование на С++: Обобщенное программирование и прикладные шаблоны проектирования STL
14.04.2012 cppNewb.ru 6
Типы указателей
обычный
сингулярный (нулевой)
нельзя разыменовывать
можно проверять на равенство
следующий за последним в массиве
нельзя разыменовывать
можно использовать в арифметике указателей и сравнениях
14.04.2012 cppNewb.ru 7
Диапазон (указателей)
[first, last) состоит из всех указателей (элементов) от first до last, не включая last
является допустимым
last достижим из first
можно разыменовывать все указатели
пустой диапазон [p, p) является допустимым
14.04.2012 cppNewb.ru 8
Диапазон (объектов)
[first, last) состоит из всех объектов (элементов) от *first до *(last-1) включительно
является допустимым
last достижим из first
можно получить адрес каждого объекта
пустой диапазон [p, p) является допустимым
14.04.2012 cppNewb.ru 9
Свойства диапазонов
если непустой диапазон [first, last) является допустимым, то [first+1, last) является допустимым
если [first, last) допустимый и указатель mid
достижим из first, last достижим из mid, то
[first, mid) и [mid, last) допустимые
если [first, mid) и [mid, last) допустимые, то
[first, last) допустимые
14.04.2012 cppNewb.ru 10