Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции С++.docx
Скачиваний:
4
Добавлен:
22.09.2019
Размер:
6.95 Mб
Скачать

Виртуальная функция

  • объявляется виртуальной в базовом классе с помощью ключевого слова 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