Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Механизм позднего связывания
При использовании виртуальных функций для каждого класса заводится своя таблица виртуальных функций Vtab, в каждой строке которой находится указатель на виртуальную функцию данного класса (т.е. адрес ее начала в ОП). В каждом объекте базового и порожденного класса хранится адрес начала этой таблицы Vptr сразу же за член-данными базовой части объекта. При вызове виртуальной функции ее адрес A(vf) вычисляется по формуле A (vf) = ((Vptr) + смещение в Vtab для этой функции). Расмотрим схему.
class A {int a, b; public: virtual void F1() {...} virtual void F2() {...} ..};
class B: public A { int a, b; public: virtual void F1() {..} virtual void F2() {..} ..};
class C: public B {int a, b; public: virtual void F1() {...} virtual void F2() {...} ..};
void main() {A x, *pa; B y(1, 2, 3, 4); C z(6, 5, 4, 3, 2, 1); pa = &z; pa –> F1();... }
Когда объявляется указатель A *pa, то его значение неопределено. При выполнении оператора pa = &z значение указателя pa становится равным адресу объекта z. Поэтому при вызове pa –> F1() адрес функции F1() = (pa –> Vptr + 0) = (VtabC + 0) и, следовательно, будет вызвана функция F1() класса C. Заметим еще раз, что адрес функции F1() всегда определяется по одному правилу в любом месте виртуального вызова, но меняется за счет разного значения ячейки Vptr у разных объектов. Таким образом, вычисление адреса виртуальной функции компилятор задает программно, но... если мы скажем волшебное слово virtual. Если функции не виртуальные, то Vtab и Vptr не формируются. Поэтому, если функции имеют одинаковое имя, но не объявлены виртуальными, берется ближайшая функция из класса для данного типа указателя (по правилу доминирования). Пример виртуальной функции, рисующей квадрат при нажатии ‘ q ’, круг при нажатии ‘ c ’, треугольник при нажатии ‘ t. ’ Перед этим 100 раз «падают» звездочки ‘ *’.
// Абстрактный базовый класс – фигура class Shape {protected: int x, y; public: Shape(int xx = 0, int yy = 0) {x = xx; y = yy;} virtual void Draw(int) = 0; // Чистая виртуальная };
// Порожденный класс – квадрат class Square: public Shape {int l; public: Square(int x, int y, int ll): Shape(x, y), l(ll) { } void Draw(int c) { … } };
// Порожденный класс – круг class Circle: public Shape {int r; public: Circle(int x, int y, int rr): Shape(x, y), r(rr) { } void Draw(int c) { … } };
// Порожденный класс – “звезда” * class Star: public Shape {public: Star(int xx, int yy): Shape(xx, yy) { }
void Draw(int c) { … } };
// Порожденный класс – треугольник class Triang: public Shape {int l; int mas[8]; // координаты вершин тр-ка public: Triang(int, int, int); // конструктор void Draw(int c) { … } };
Triang:: Triang(int xx, int yy, int ll): Shape(xx, yy) {int i; l = ll; float r, a, da; // a – угол, da – приращение угла r = l / sqrt(3); da = 6.28 / 3; for(i = 0, a = 3.14 / 2; i < 6; a = a + da) { mas[i++] = x + int(r * cos(a)); mas[i++] = y - int(r * sin(a)); } mas[i++] = mas[0]; mas[i] = mas[1]; }
void main() {Shape *psh; // Указатель на базовый класс int i, k; char s; // определяем 3 объекта Square q(300, 200, 100); // квадрат Circle c(300, 100, 50); // круг Triang t(300, 100, 100); // треугольник for(i = 0; i < 100; i++) {psh = new Star(random(640) + 2, random(400) + 2); psh –> Draw(random(15) + 1); // выводятся случайные '*' delete psh; } cin >> s; switch(s) // клавиша нажата, какая? {case 's': psh = &q; break; // занести адрес объекта “квадрат” case 'c': psh = &c; break; // занести адрес объекта “круг” case 't': psh = &t; break; // занести адрес объекта “треугольник” case 13: return; default:: continue; // иначе продолжить } if (k = random(15) + 1) == 7) k =5; psh –> Draw(k); // Виртуальный вызов виртуальной функции Draw() }
Итоговая таблица
|
|||||||||||||||||||||||||
Последнее изменение этой страницы: 2021-12-07; просмотров: 37; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.128.199.162 (0.005 с.) |