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

5.5. Механизм позднего связывания

При использовании виртуальных функций для каждого класса заводится своя таблица виртуальных функций 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( )

}

Итоговая таблица

Выходные параметры

Имя функции

Входные параметры

Тело функции

Перегруженная функция

разные

одинаковое

разные

разное

Функция-шаблон

разные

одинаковое

разные

одинаковое

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

одинаковое

одинаковое

Одинаковое

разное

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