close

Вход

Забыли?

вход по аккаунту

код для вставкиСкачать
09.06.2014
Программирование
с использованием C++11
Полевой Дмитрий Валерьевич
к.т.н., доцент КиК
e-mail: [email protected]
1
09.06.2014
Перечисления (С++98)
enum
• экспортируют имена в окружающую
область видимости
(возможны конфликты имен)
• неявно преобразуются в целый тип
(нет строгого контроля типов)
28.05.2014
2
2
09.06.2014
Перечисление (С++11)
enum class
• имена не экспортируются
• элементы могут иметь определенный тип
• строгий контроль типов
28.05.2014
3
3
09.06.2014
Перечисление (пример)
#include <cstdint>
enum class Colors : uint8_t
{
RED = 1,
GREEN = 2,
BLUE = 3
};
28.05.2014
4
4
09.06.2014
l-value
• C
«left hand side value»
то, чему можно присвоить значение
• С++98
выражение, ссылающееся на объект
можно получить адрес
28.05.2014
5
5
09.06.2014
r-value
• С++98
– все, что не l-value
– не является объектом
– нельзя получить адрес
28.05.2014
6
6
09.06.2014
C++11
•
•
•
•
•
l-value
r-value
x-value («expiring value»)
gl-value – обобщение l-value и x-value
pr-value – узкая специализация r-value
28.05.2014
7
7
09.06.2014
Ссылка
• l-value ссылка
T& r{val};
альтернативное имя для объекта
• r-value ссылка
T&& r{f(x)};
альтернативное имя для «неименуемого» объекта
отличный от l-value ссылки тип
28.05.2014
8
8
09.06.2014
Обмен значений (C++98)
template<class T>
void swap(T& a, T& b)
{
T newB{a}; // копирование!
a = b;
b = newB;
}
28.05.2014
9
9
09.06.2014
Обмен значений (C++11)
template<class T>
void swap(T& a, T& b)
{
T newB{std::move(a)};
a = std::move(b);
b = std::move(newB);
}
28.05.2014
10
10
09.06.2014
Конструирование с перемещением
// перемещающий конструктор копии
T(T&& obj)
// перемещающий оператор присваивания
T& operator=(T&& obj)
28.05.2014
11
11
09.06.2014
Конструктор копирования и
наследование
// обычный - copy semantics
Base(Base const& rhs);
// перемещающий - move semantics
Base(Base&& rhs);
28.05.2014
12
12
09.06.2014
Конструктор копирования
(производный класс)
Derived(Derived const & rhs) :
Base(rhs) {};
// rhs – именованный объект
// Derived(Derived&& rhs) :
// Base(rhs) {};
Derived(Derived&& rhs) :
Base(std::move(rhs)) {};
28.05.2014
13
13
09.06.2014
Перемещающий конструктор
(пример)
MemBlock(MemBlock&& other)
: pData_{other.pData_}
{
other.pData_ = nullptr;
}
28.05.2014
14
14
09.06.2014
Перемещающий оператор присваивания
(пример)
MemBlock& operator=(MemBlock&& other)
{
if (this != &other)
{
delete[] pData_;
other.pData_ = nullptr;
}
return *this;
}
28.05.2014
15
15
09.06.2014
Свёртка ссылок
• определения typedef и decltype
• параметры шаблонов
A& &
A& &&
A&& &
A&& &&
28.05.2014
A&
A&
A&
A&&
16
16
09.06.2014
Полиморфизм
• полиморфный – “имеющий много форм”
• взаимозаменяемость объектов с
одинаковым интерфейсом
• использование одного имени для разных
задач (реализаций)
28.05.2014
17
17
09.06.2014
Тип и класс
• тип определяется интерфейсом, т.е.
набором допустимых операций
• класс реализует один или несколько типов
• интерфейс класса м.б. шире, чем интерфейс
типа
28.05.2014
18
18
09.06.2014
Повышающее приведение типа
• интерпретация адреса экземпляра
производного класса в качестве адреса
экземпляра базового класса
(через указатель или ссылку)
• “сужает” интерфейс производного класса
до интерфейса базового
• допустимо при соблюдении
подстановочного принципа
28.05.2014
19
19
09.06.2014
Повышающее приведение типа (пример)
//class Student : public Man
void
protocol(ostream& os, const Man& man)
{
printHeader(os);
man.writeTxt(os);
printFooter(os);
}
28.05.2014
20
20
09.06.2014
Связывание
• соотнесение вызова функции с телом функции
• раннее связывание
– реализуется компилятором и компоновщиком до
запуска программы (при “сборке”)
• позднее (динамическое) связывание
– осуществляется в процессе исполнения
программы в зависимости от фактического типа
экземпляра
28.05.2014
21
21
09.06.2014
Виртуальная функция
• объявляется виртуальной в базовом классе с
помощью ключевого слова virtual
• связывается динамически при
использовании адреса базового класса
• остается виртуальной во всех производных
классах (достаточно одного объявления в
базовом классе)
28.05.2014
22
22
09.06.2014
Использование virtual
• избегайте использования virtual в
определениях функций
• избегайте использования virtual в
объявлениях производных классов
• переопределение – повторное
определение виртуальной функции в
производном классе
28.05.2014
23
23
09.06.2014
Виртуальная функция (пример)
class Man
{
public:
virtual void writeTxt(ostream& os);
…
};
void
Man::writeTxt(ostream& os)
…
28.05.2014
24
24
09.06.2014
Расширяемость
• универсальный код
– взаимодействует только с интерфейсом типа
(т.е. базового класса)
• возможно добавление новых производных
классов, без изменения универсального
кода
28.05.2014
25
25
09.06.2014
Поиск тела виртуальной функции
• компилятор гарантирует наличие тела для
виртуальной функции
• если виртуальная функция не
переопределяется в классе, то вызывается
“ближайшее” в иерархии наследования
определение
28.05.2014
26
26
09.06.2014
Расширяемость (пример)
//Student : public Man
//Tutor : public Man
void
printStat(ostream& os, Man** pPeople)
{
…
(pPeople + iCur)->writeTxt(os);
…
}
28.05.2014
27
27
09.06.2014
Типичная реализация позднего
связывания
• таблица виртуальных функций VTABLE для
каждого класса, содержащего виртуальные
функции
• скрытое хранение указателя VPTR на VTABLE
в каждом экземпляре класса
• автоматическая генерация кода доступа к
функции через VTABLE в точке вызова
полиморфной функции
28.05.2014
28
28
09.06.2014
Размещение в памяти
• классы без данных приводятся компилятором
к ненулевому размеру за счет вставки
фиктивной переменой
• каждый экземпляр класса с виртуальными
функциями хранит скрытый указатель VPTR
(перед данными)
• в классах без данных с виртуальными
функциями место фиктивной переменной
занимает указатель VPTR
28.05.2014
29
29
09.06.2014
Схема хранения VTABLE
таблица виртуальных
функций
объект Man
- vptr
Man::writeTxt
Man::readTxt
объект Student
- vptr
Student::writeTxt
Student::readTxt
объект Tutor
- vptr
Tutor::writeTxt
Tutor::readTxt
28.05.2014
30
30
09.06.2014
Инициализация указателя VPTR
• виртуальные функции не должны
вызываться до инициализации VPTR
• инициализация VPTR происходит в
конструкторе (в т.ч. умолчательном)
28.05.2014
31
31
09.06.2014
Наследование и VTABLE
• при создании экземпляра класса в таблицу
заносится адреса определенных в классе
виртуальных функций
• при добавлении в производном классе
новых виртуальных функций таблица
расширяется
28.05.2014
32
32
09.06.2014
Повышающее приведение и объекты
• повышающее приведение типа применимо
только к адресам (ссылкам)
• если в точке вызова тип точно известен,
используется раннее связывание
(как типичное поведение компилятора)
28.05.2014
33
33
09.06.2014
Эффективность использования
виртуальных функций
• минусы
– дополнительные инструкции для каждого
вызова виртуальной функции
– дополнительный код для инициализации
– дополнительная память для хранения
• плюсы
– повышение гибкости программ
– повышение эффективности работы
программистов
28.05.2014
34
34
09.06.2014
Чисто виртуальная функция
• объявление начинается с virtual и
заканчивается “= 0”
• должна реализовываться в производном
классе
пример:
virtual int func() = 0;
28.05.2014
35
35
09.06.2014
Объявление чисто виртуальной функции
• резервирует ячейку в таблице виртуальных
функций VTABLE
• не заносит конкретного указателя на
реализацию функции
• указывает способ использования класса
28.05.2014
36
36
09.06.2014
Абстрактный класс
• содержит нереализованные чисто
виртуальные функции
• создание экземпляров абстрактных классов
запрещено
• при наследовании от абстрактного класса
все чисто виртуальные функции д.б.
реализованы
28.05.2014
37
37
09.06.2014
Абстрактный класс как тип
• определяет тип (интерфейс)
• используется в качестве базового в
иерархии наследования для классов
реализующих данный интерфейс
• используется в реализации алгоритмов над
объектами типа
28.05.2014
38
38
09.06.2014
Использование абстрактных классов
• запрещает передачу экземпляров по
значению
• гарантирует осуществление повышающего
приведения типа через указатель или
ссылку
28.05.2014
39
39
09.06.2014
Определение чисто виртуальной
функции
• аналогично обычной функции
• класс остается абстрактным
• позволяет вызывать общий код в
производных классах
28.05.2014
40
40
09.06.2014
Определение чисто виртуальной
функции (пример)
class Printable
{
public:
virtual void writeTxt(ostream& os) = 0;
};
void Printable::writeTxt(ostream& os)
{
// общий код
}
// class Man
28.05.2014
: public Printable
41
41
09.06.2014
Изменение типа возвращаемого
значения
• возможно
• функция базового класса
– возвращает указатель или ссылку на базовый
класс
• переопределенная функция
– может возвращать указатель или ссылку на
производный класс
28.05.2014
42
42
09.06.2014
Особенности конструкторов и
деструкторов
• код инициализации VPTR вставляется в
конструктор
• механизм виртуального вызова не работает
в конструкторах и деструкторах
28.05.2014
43
43
09.06.2014
Виртуальный деструктор
• нужен для правильно разрушения объекта
производного класса через
указатель/ссылку базового класса
• деструктор базового класса обязательно
д.б. виртуальным
пример:
virtual ~Base();
28.05.2014
44
44
09.06.2014
Чисто виртуальный деструктор
• имеет право быть
• должен иметь тело
• предотвращает возможность создания
экземпляров класса
28.05.2014
45
45
09.06.2014
Виртуальный вызов (C++11)
override
– переопределение виртуального метода в
базовом классе
final
– производный класс не должен переопределять
виртуальный метод
28.05.2014
46
46
09.06.2014
«Умные» указатели
• unique_ptr
– ресурс не разделяемый (нет конструктора
копирования
– может быть передан другому unique_ptr
• shared_ptr
– ресурс разделяемый (считает ссылки)
• weak_ptr
– ссылка на объект, которым управляет shared_ptr
– не осуществляет подсчет ссылок
– позволяет избавиться от циклической зависимости
28.05.2014
47
47
1/--страниц
Пожаловаться на содержимое документа