240-1677 (Объективное программирование), страница 6

2016-07-31СтудИзба

Описание файла

Документ из архива "Объективное программирование", который расположен в категории "". Всё это находится в предмете "информатика" из , которые можно найти в файловом архиве . Не смотря на прямую связь этого архива с , его также можно найти и в других разделах. Архив можно найти в разделе "рефераты, доклады и презентации", в предмете "информатика, программирование" в общих файлах.

Онлайн просмотр документа "240-1677"

Текст 6 страницы из документа "240-1677"

void f();

void newf(); // Новая функция f() с идентификацией ПК

}

a::a() // Конструкторы объектов

{ ...

id = 0;

}

b::b()

{ ...

id = 1;

}

c::c()

{ ...

id = 2

}

void a::newf()

{

switch (id)

{

case 0: a::f(); break;

case 1: b::f(); break;

case 2: c::f(); break;

}

}

p[0]->newf(); // Вызов b::f() для B1

p[1]->newf(); // Вызов c::f() для C1

p[2]->newf(); // Вызов a::f() для А1

Отсюда следует определение виртуальной функции. Виртуальная функция (ВФ) - это функция, определяемая в базовом и наследуемая или переопределяемая в производных классах. При вызове ее по ссылке на объект базового класса происходит вызов той функции, которая соответствует классу объекта, включающему в себя данный объект базового класса.

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

Реализация механизма виртуальных функций заключается в создании компилятором таблицы адресов виртуальных функций (ссылок).

Такая таблица создается для базового класса и для каждого включения базового класса в производный. В объекте базового класса создается дополнительный элемент - ссылка на таблицу адресов его виртуальных функций. Эта ссылка устанавливается конструктуром при создании объекта производного класса. При вызове виртуальной функции по ссылке на объект базового класса из объекта берется ссылка на таблицу функций и из нее берется адрес функции по фиксированному смещению. Ниже иллюстрируется реализация этого механизма (подчеркнуты элементы, создаваемые неявно компилятром).

class A

{

------> void (**ftable)(); // Ссылка на таблицу адресов

// виртуальных функций

public:

virtual void x();

virtual void y();

virtual void z();

A();

~A();

};

// Таблица адресов функций класса А

------> void (*TableA[])() = { A::x, A::y, A::z };

A::A()

{

------> ftable = TableA; // Установка таблицы для класса А

}

class B : public A

{

public:

void x();

void z();

B();

~B();

};

// Таблица адресов функций класса A

// в классе B

--> void (*TableB[])() = { B::x, A::y, B::z };

¦ L переопределяется в B

B::B() L------ наследуется из A

{

--> ftable = TableB; // Установка таблицы для класса B

}

void main()

{

A* p; // Ссылка p базового класса A

B nnn; // ссылается на объект производp = &nnn; // ного класса B

реализация

p->z(); ------------------> (*(p->ftable[2]))();

}

p nnn TableB B::z()

-----¬ -------->--B-----¬ ----->---------¬ --->----------¬

¦ ------ ftable¦--A---¬¦ ¦ 0+--------+ ¦ ¦ ¦

L----- ¦¦ ------ 1+--------+ ¦ ¦ ¦

¦+-----+¦ 2¦ --------- L--------- ¦¦ ¦¦ L--------

7.2 Абстрактные классы

---------------------

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

быть "пустыми", поскольку никогда не будут вызваны для объекта

базового класса. Такой базовый класс называется абстрактным. Виртуальные функции в определении класса обозначаются следующим образом:

class base

{

public:

virtual print() =0;

virtual get() =0;

}

Естественно, что определять тела этих функций не требуется.

7.3 Множественное наследование и виртуальные функции

---------------------------------------------------

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

Существенным для реализации множественного наследования является

то, что адреса объектов второго и т.д. базовых классов не совпадают с адресом объекта производного и первого базового классов,

то есть имеют фиксированные смещения относительно начала объекта:

class d : public a,public b, public c { };

d D1;

pd = &D1; // #define db sizeof(a)

pa = pd; // #define dc sizeof(a)+sizeof(b)

pb = pd; // pb = (char*)pd + db

pc = pd; // pc = (char*)pd + dc

D1

pd -------------------->-d---------¬

pa --------------------->-a-------¬¦T T

¦¦ ¦¦¦ ¦ db = sizeof(a)

¦L---------¦¦ +

pb --------------------->-b-------¬¦¦ dc = sizeof(a) + sizeof(b)

¦L---------¦¦

pc --------------------->-c-------¬¦+

¦L---------¦

¦ ¦

L----------

Преобразование ссылки на объект производного класса к ссылке

на объект базового класса требует добавления к указателю текущего

объекта this соответствующего смещения (db,dc), обратное преобразование - вычитание этого же смещения. Такое действие выполняется

компилятором, когда в объекте производного класса наследуется

функция из второго и т.д. базового класса, например при определении в классе "b" функции "f()" и ее наследовании в классе "d" вызов D1.f() будет реализован следующим образом:

this = &D1; // Адрес объекта производного класса

this = (char*)this + db // Адрес объекта класса b в нем

b::f(this); // Вызов функции в классе b со своим

// объектом

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

множественном наследовании. Во-первых, на каждый базовый класс в

производном классе создается своя таблица виртуальных функций (в

нашем случае - для "a" в "d", для "b" в "d" и для "c" в "d").

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

ссылку на объект базового класса в ссылку на объект производного,

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

class a

{

public: virtual void f();

virtual void g();

};

class b

{

public: virtual void h();

virtual void t();

};

class c : public a, public b

{ // f(),t() наследуются

public: void g(); // g() переопределяется

void h(); // h() переопределяется

}

a A1;

b B1;

c C1;

pa = &A1;

pb = &B1;

pa->f(); // Вызов a::f()

pb->h(); // Вызов b::h()

pa = &C1;

pb = &C1;

pa->f(); // Вызов a::f()

pa->g(); // Вызов c::g()

pb->h(); // Вызов c::h()

pb->t(); // Вызов b::t()

Таблицы виртуальных функций для данного примера имеют вид:

A1

-a----¬ Таблица ВФ для "a"

¦ ------------>--------¬

+-----+ ¦a::f() ¦

L------ +-------+

¦a::g() ¦

L------- B1

-b----¬ Таблица ВФ для "b"

¦ ------------>--------¬

+-----+ ¦b::h() ¦

L------ +-------+

¦b::t() ¦

L------- C1

T --c-----¬ Таблица ВФ для "a" в "c"

¦ ¦--a---¬¦ --------¬

db ¦ ¦¦ ----------->¦a::f() ¦

¦ ¦L------¦ +-------+

+ ¦--b---¬¦ ¦c::g() ¦

¦¦ -------¬ L------- ¦L------¦ ¦ Таблица ВФ для "b" в "c"

¦ ¦ ¦

¦ ¦ L--->--------¬ "Заплата" для c::h()

L-------- ¦ xxx()----->--xxx()----------------¬

+-------+ ¦ this=(char*)this - db¦

¦b::t() ¦ ¦ goto c::h ¦

L-------- L----------------------

Другим вариантом решения проблемы является хранение необходимых смещений в самих таблицах виртуальных функций.

7.4. Виртуальные базовые классы

------------------------------

В процессе иерархического определения производных классов

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

несколько объектов базового класса, например

class base {}

class a : public base {}

class b : public base {}

class c : a, b {}

В классе "c" присутствуют два объекта класса base. Для исключения такого дублирования объект базового класса должен быть

объявлен виртуальным

class a : virtual public base {}

class b : virtual public base {}

class c : public a, public b {}

a A1;

b B1;

c C1;

Объект обыкновенного базового класса располагается, как правило, в начале объекта производного класса и имеет фиксированное

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

класса на соответствующем месте размещается не объект базового

класса, а ссылка на него, которая устанавливается конструктором.

Для вышеприведенного примера имеем

A1 B1 C1

--a------¬ --b-----¬ --c---------------¬

¦ ------¬ ¦ ------¬ ¦ --a-------¬ ¦

+--------+ ¦ +-------+ ¦ ¦ ¦ -------¬ ¦

¦ ¦ ¦ ¦ ¦ ¦ ¦ +---------+ ¦ ¦

¦-base--¬<---- ¦-base-¬<---- ¦ ¦ ¦ ¦ ¦

¦L-------¦ ¦L------¦ ¦ L---------- ¦ ¦

L--------- L-------- ¦ --b-------¬ ¦ ¦

¦ ¦ ------¬¦ ¦

¦ +---------+ ¦¦ ¦

¦ ¦ ¦ ¦¦ ¦

¦ L---------- ¦¦ ¦

¦ -base---¬<---¦ ¦

¦ L--------<---- ¦

L-----------------

Таблицы виртуальных функций располагаются в каждом базовом

классе обычным образом.

Лекция 8. Пример использования виртуальных функций

-------------------------------------------------

Реляционная база данных (РБД) представляет собой таблицу,

состоящую из произвольного количества строк и столбцов. В качестве элементов, хранящихся в клетке такой таблицы могут быть целые,

вещественные числа, строки постоянной и переменной длины, значения даты и времени. Все типы элементов в одном столбце должны

совпадать. Количество строк и столбцов, названия столбцов и типы

элементов в них заранее не известны и определяются динамически,

то есть в процессе работы программы.

В нашем примере рассмотрим РБД, целиком размещенную в памяти.

8.1 Организация РБД в виде таблиц ссылок на объекты

--------------------------------------------------

Прежде всего, определим элементы, размещенные в клетках таблицы, как объекты соответствующих элементарных классов:

- class string - строки переменной длины;

- class integer - целые числа;

- class real - вещественные числа;

- class dat - дата;

- class time - время и т.д.

Перечень таких классов может быть расширен. Для каждого из

них необходимо определить множество функций и операций, который

будет использоваться при работе с таблицей: ввод и вывод значения

объекта, сравнение объектов, создание копии объекта, приведение к

базовым типам данных (int, long, char*), арифметических операций

над объектами и целыми и т.д.. Интерпретация последних должна

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

В качестве примера рассмотрим класс строк переменной длины.

class string : base

{

char *s; // Ссылка на строку

int sz; // Длина строки

public: int GET(); // Ввод строки

void PUT(); // Вывод строки

int CMP(base*); // Сравнение строк

char *NAME(); // Возвращает имя класса строк

base *COPY(); // Возвращает копию объекта

operator long(); // Преобразование к типу long // возвращает длину строки

operator char*(); // Преобразование к типу char* // возвращает копию строки

base& operator+(char*); // Операция "+ строка"

// присоединяет строку

string();

~string();

}

//------------------------------------------------------string::string() // Конструктор

{

s = NULL; // Строка пустая

sz = 0;

}

//------------------------------------------------------string::~string() // Деструктор

{

if (s !=NULL) delete s; // Освободить память

}

//------------------------------------------------------int string::GET()

{

char ss[80];

if (s !=NULL) delete s;

gets(ss); // Ввод строки и размещение ее

s = new char[sz = strlen(ss)+1];// в динамической памяти

strcpy(s,ss);

return(1); // Ввод всегда правильный

}

//------------------------------------------------------void string::PUT()

{ puts(s); }

//------------------------------------------------------int string::CMP(base* two) // Сравнение строк по алфавиту

{

string *p = (string*) two; // Преобразовать ссылку на

return(strcmp(s, p->s); // второй объект к классу строк

} // (переход от БК к ПК)

//-------------------------------------------------------char *string::NAME() // Возвращает имя класса строк

{ return("Строка"); }

//-------------------------------------------------------base *string::COPY() // Создание копии объекта

{ // без копирования значения

string *p = new string; //

return(p); //

}

//-------------------------------------------------------string::operator long() // Преобразование к типу long { // возвращает длину строки

return (sz);

}

//-------------------------------------------------------string::operator char*() // Преобразование к типу char* { // возвращает текстовое представchar *p = new char[sz]; // ление значения объекта

strcpy(p,s);

return(p);

}

//--------------------------------------------------------base& string::operator+(char* two) // Операция "+ строка"

{ // Конкатенация строки в объекте

char ss[80]; // и входной строки

strcpy(ss,s); //

strcat(ss,two);

delete s;

s = new char[sz = strlen(ss)+1];

strcpy(s,ss);

return(*(base*)this); // Возвратить неявную ссылку на объект

} // вложенного базового класса

//-------------------------------------------------------

Базовый класс "base" необходим исключительно для обеспечения

идентичного доступа к любому элементу базы данных независимо от

его класса. Это абстрактный класс, содержащий объявление всех вышеперечисленных функций и операций виртуальными.

class base

{

public:

virtual int GET()=0; // Ввод значения объекта

virtual void PUT()=0; // Вывод значения объекта

virtual int CMP(base*)=0; // Сравнение значений объектов

virtual char *NAME()=0; // Возвращает имя класса

virtual base *COPY()=0; // Возвращает копию объекта

virtual operator long()=0; // Преобразование к типу long

virtual operator char*()=0; // Преобразование к типу char*

virtual base& operator+(char*)=0;

// Операция "+ строка"

virtual ~base(); // Виртуальный деструктор для

// разрушения объекта ПК по

}; // ссылке на БК

Сама двумерная таблица объектов организована традиционным

для структур переменной размерности способом:

- элемент БД создается в динамической памяти при добавлении

строки к БД;

- строка БД представлена массивом ссылок на объекты класса

base. Сам массив также создается в динамической памяти при добавлении новой строки в БД;

- ссылки на строки собраны в массив, который создается

конструктором базы данных и заполняется при вызове функции добавления строки (таблица строк БД);

- объект класса БД (table) содержит ссылку TBL на таблицу

строк.

Особо следует остановиться на способе назначения столбцам

типов содержащихся в них элементов БД (или классов объектов). Это

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

виртуальной функцией COPY создаются копии объектов из строки заголовка БД, для которых затем вызывается виртуальная функция ввода значений GET.

Строка заголовка создается конструктором объекта класса БД.

Имеется меню типов элементов, которое представляет собой массив

ссылок (TYPE) на объекты классов string,integer,dat и т.д.. Экранное меню строится при помощи вызова виртуальной функции вывода

имени класса TYPE[i]->NAME(). После выбора строки меню ссылка на

соответствующий выбранный объект переносится в строку заголовка БД.

class table

{

int nc; // Количество столбцов

int nr; // Количество строк

char **names; // Имена стробцов

base **head; // Строка объектов заголовка БД

// для объявления типов объектов

base ***TBL; // Таблица строк БД

public:

void append(); // Добавление строки в БД

void sort(int); // Сортировка по значениям столбца

long averrage(int); // Подсчет среднего арифметического

// для столбца

base& operator()(int,int);

// Выбор объекта из БД

table(); // Конструктор - создание БД

~table(); // Деструктор - удаление БД

}

объект БД

TBL Массив строк БД

--¬ ---------¬0

¦------->+--------+.. Элемент БД

L-- +--------+i Строка БД string

base*** ¦ ----------->---------¬0 integer

+--------+ +--------+.. real

+--------+ +--------+j --dat-------¬

base** ¦ -------------->-base-----¬¦

Свежие статьи
Популярно сейчас
Зачем заказывать выполнение своего задания, если оно уже было выполнено много много раз? Его можно просто купить или даже скачать бесплатно на СтудИзбе. Найдите нужный учебный материал у нас!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
5167
Авторов
на СтудИзбе
438
Средний доход
с одного платного файла
Обучение Подробнее