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


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

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



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