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

Void do_(a& a)

{

a.f();

a.g();

}

Void main()

{

A a;

B b;

do_(a);

do_(b);

}

Результатом програми буде таке виведення:

Функція А::f()

Функція А::g()

Функція А::f()

Функція B::g()

Звертання до do_(A&) з об’єктом В призводить до виклику функцій A::f() і B::g(). Це відбувається тому, що при виклику функції do_(b) посилання В& неявно перетвориться в A&. Компілятор бачить, що A::f() – невіртуальна функція і генерує пряме звертання до A::f(). Виклик функції a.g() у do_(A&) опрацьовується інакше, оскільки компілятор виявляє, що g() у класі А оголошена віртуальною. Це призводить до генерації коду, що включає механізм опрацювання віртуальних функцій. Розміщення об’єктів у пам’яті показано на рисунку 4.4.

Під час виконання код використовує таблицю по вказівці vprt в об’єкті класу В, щоб визначити яку функцію викликати при звертанні до g(), і знаходить B::g(). Поле vptr класу В знаходиться в тій же позиції, що і vptr класу А, так що do_(A&) одержує доступ до коректної функції, незалежно від того, який тип об’єкта передається в do_(A&). Проте зверніть увагу на те, що vptr для об’єкта класу А і vptr для об’єкта класу В посилаються на різні таблиці vtbl.

Змінна

Зсув

a -> A::

Vptr

a

0

4

A::vtbl

&A::g

Змінна

Зсув

a -> A::

b-> B::

Vptr

a

b

0

4

8

B::vtbl

&B::g

Рис. 4.4. Розміщення двох об’єктів в пам’яті

Приклад розміщення об’єктів в пам’яті:

#include <iostream>

using namespace std;

class A

{

public:

int a;

A(int a){this->a = a;}

virtual void PrintOn() {puts("Okey - A");}

static int dd(){ return 10;}

};

class B: public A

{

public:

B(int b):A(100){this->b = b;}

int b;

virtual void PrintOn() {puts("Okey - B");}

};

class C: public A

{

public:

C(int c):A(500){this->c = c;}

int c;

virtual void PrintOn() {puts("Okey - C");}

};

Void show(a* a)

{

a->PrintOn();

}

Void main()

{

B *b = new B(400);

C *c= new C(600);

show(b); //використовується B::PrintOn()

show(c); //використовується C::PrintOn()

A*a = b;

a->PrintOn();

cout <<" --" << ((B*)a)->b <<"\n";

a = c;

a->PrintOn();

// розміри

cout <<"size a - "<< sizeof(*a) <<" size b - "

<<sizeof(*b)<<" "<<"size c - "<< sizeof(*c) <<"\n";

int* in = (int*)b;

cout << *in << " " <<*(in + 1)<<" "<<*(in + 2);

cout << endl;

in = (int*)c;

cout << *in << " " <<*(in + 1)<<" "<<*(in + 2);

cout << "\n"<<A::dd();

delete b,c;

}

Результат виконання програми буде виглядати наступним чином:

Okey - B

Okey - C

Okey - B

--400

Okey - C

size a - 8 size b - 12 size c - 12

4290624 100 400

4290672 500 600

10

Завдання

Завдання отримуються з розділу 3 "Спадкування класів" та доповнюються віртуальними функціями.

Розділ 5. Перевантаження операторів

5.1 Загальні відомості

C++ дозволяє перевизначити дію більшості операторів так, щоб при використанні з об'єктами конкретного класу вони виконували задані функції. Це дає можливість використовувати власні типи даних точно так, як і стандартні. Позначення власних операторів вводити не можна. Можна перенавантажувати будь-які оператори, що існують в C++, за виключенням:

* ? ### sizeof

Перевантаження операторів здійснюється за допомогою методів спеціального вигляду { функцій-операцій) і підкоряється наступним правилам:

  • при перевантаженні операторів зберігаються кількість аргументів, пріоритети операторів і правила асоціації (справа наліво або зліва направо), які використовуються в стандартних типах даних;

  • для стандартних типів даних перевизначати оператори не можна;

  • функції-оператори не можуть мати аргументів за умовчанням;

  • функції-оператори успадковуються (за виключенням =);

  • функції-оператори не можуть визначатися як static.

Функцію-оператор можна визначити трьома способами:

  • методом класу (реалізація усередині класу);

  • дружньою функцією класу;

  • звичайною функцією;

У двох останніх випадках функція повинна приймати хоч би один аргумент, що має тип класу, вказівки або посилання на клас.

Функція-оператор містить ключове слово operator, за яким слідує знак оператора, який треба перевизначити.

тип operator оператор ( список параметрів) { тіло функції }