Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
sp_lb3.doc
Скачиваний:
2
Добавлен:
14.11.2019
Размер:
99 Кб
Скачать
☆

3.3Полиморфизм

Поддержка виртуальных функций является важной характеристикой в объектно-ориентированном программировании и называется полиморфизмом.

Полиморфизм - это способность использовать одну и ту же инструкцию для выполнения любого из множества различных действий. Действие, выполняемое в данный момент, определяется типом объекта, над которым производится действие. Пример полиморфизма — вызов одной и той же функции:

PFrm->Draw();

для рисования прямоугольников, окон и окон с закругленными углами. Действие, выполняемое в каждом конкретном случае, определяется классом объекта, который в данный момент адресует указатель PFrm.

3.4Конкретные и абстрактные классы

Многие классы сходны с классом CFrame тем, что в них можно дать разумное определение виртуальных функций, если они есть, и объекты которых можно объявлять. Классы, объекты которых могут быть реализованы, называются конкретными классами. Однако есть и другие классы. Некоторые, например, такие как представленный ниже класс абстрактной фигуры CShape, представляют собой абстрактные понятия, для которых нельзя создавать объекты.

Абстрактный класс CShape приобретает смысл только как базовый класс для некоторых производных классов. Причиной является то, что невозможно дать осмысленное определение виртуальных функций класса CShape:

class CShape

{

// ...

public:

// нельзя ни вращать, ни рисовать абстрактную фигуру

virtual void rotate(int){error("CShape::rotate"); }

virtual void draw(){error("CShape::draw"); }

// ...

};

Создание объекта класса CShape (абстрактной фигуры) - законная, хотя совершенно бессмысленная операция:

CShape s; // лишено смысла

Она бессмысленна потому, что любая операция с объектом s приведет к выдаче сообщения об ошибке. В таких случаях лучше виртуальные функции класса CShape объявить как чисто виртуальные. Сделать виртуальную функцию чисто виртуальной можно, добавив в конце её объявления инициализатор "= 0":

class CShape

{

// ...

public:

virtual void rotate(int) = 0; // чисто виртуальная функция

virtual void draw() = 0; // чисто виртуальная функция

};

Чисто виртуальной функцией называется виртуальная функция, в объявлении которой её тело определено как 0, т. е. его нельзя определить в рамках базового класса. Класс, в объявлении которого имеется одна или несколько чисто виртуальных функций, называется абстрактным классом. Объекты абстрактного класса создавать нельзя, так как он имеет нереализованные функции:

CShape s; // ошибка: переменная абстрактного класса CShape

Абстрактный класс можно использовать только в качестве базового при создании другого класса.

3.5Внутренняя реализация виртуальных функций и полиморфизма

Для реализации виртуальных функций и полиморфизма компиляторы пользуются технологией преобразования имени виртуальной функции в индекс в таблице, содержащей указатели на функции. Такая таблица представляет собой одномерный массив указателей на функции и называется таблицей виртуальных функций (virtual function table - vtbl).

Каждый класс с виртуальными функциями имеет свою собственную таблицу виртуальных функций, идентифицирующую его виртуальные функции.

Для базового класса Character_device таблицу виртуальных функций можно представить графически так, как это показано на рис. 3.1.

0

open

1

close

2

read

3

write

4

ioctl

5

~Character_device

Рисунок 3.1 Таблица виртуальных функций

Таблица vtbl содержит указатели на виртуальные функции класса, имена которых указаны в соответствующих ячейках на рисунке. Слева от ячеек с именами функций указаны номера этих функций в таблице vtbl. В базовом классе ячейки массива для чисто виртуальных функций устанавливаются в 0, что соответствует приравниванию нолю объявления соответствующей виртуальной функции. Для каждого производного класса делается копия таблицы vtbl его прямого базового класса. При этом для переопределённых в производном классе виртуальных функций нулевые указатели в ячейках vtbl замещаются указателями на реализации соответствующих функций.

Каждый объект базового или производного класса с виртуальными функциями содержится в своем участке памяти, и в памяти каждого объекта имеется ссылка на общую для всех объектов этого класса таблицу vtbl:

Объект 1

Объект 2

-4

Указатель vtbl

->

Vtbl класса

<-

Указатель vtbl

-4

0

open

0

close

read

write

ioctl

~Character_device

Рисунок 3.2 Взаимосвязь объектов с таблицей виртуальных функций

При вызове виртуальной функции через указатель на объект базового класса (полиморфизм) из памяти объекта со смещением в +4 по отношению к значению указателя осуществляется выборка указателя (базового адреса) таблицы виртуальных функций класса – vtbl. После этого указатель на vtbl индексируется номером виртуальной функции, из элемента таблицы выбирается указатель на соответствующую номеру виртуальную функцию, после чего осуществляется косвенный вызов функции через указатель.

Так как в базовом и производном классах указатели на виртуальные функции всегда находятся в одних и тех же по номеру элементах vtbl, всегда вызывается реализация виртуальной функции, соответствующая классу объекта.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]