Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
8
Добавлен:
12.02.2016
Размер:
353.16 Кб
Скачать

};

 

int main() {

 

int cl::*data;

// Вказівник на член класу

int (cl::*func)();

// Вказівник на функцію-член

cl obl(l), ob2(2);

// Створюємо об'єкти

data = &cl::val;

// Визначаємо зсув члена val

func = &cl::double_val;

// Визначаємо зсув функції double_val()

cout << "Значення: ";

cout << obl.*data << " " << ob2.*data << "\n"; cout << "Подвоєні значення: ";

cout << (obl.*func)() << " "; cout << (ob2.*func)() << "\n"; return 0;

}

Ця програма створює два вказівники на члени класу: data і func. Зверніть особливу увагу на синтаксичні особливості їхніх оголошень. Оголошуючи вказівники на члени, варто задавати ім'я класу й застосовувати оператор дозволу області видимості. Крім того, програма створює два об'єкти класу c1: ob1 і оb2. Вказівники на члени класу можуть посилатися як на змінні, так і на члени. Потім обчисляються адреси членів val і double_val(). Ці "адреси" являють собою зсув відповідних членів в об'єкті класу cl. Значення, що

21/54

зберігаються в змінній val у кожному з об'єктів, виводяться на екран за допомогою вказівника data. На закінчення, програма викликає функцію double_func(), використовуючи змінну func, що є вказівником на член класу. Зверніть увагу на те, що для правильного виконання оператора " *" необхідні додаткові дужки.

Для доступу до члена класу через об'єкт або посилання на нього використовується оператор " *". Якщо задано вказівник на об'єкт, для доступу до його членів необхідно застосовувати оператор "->*". Проілюструємо сказане наступним прикладом.

#include <iostream> using namespace std; class cl {

public:

cl(int i) { val=i; } int val;

int double_val() { return val+val;

};

 

int main ()

 

{

 

int cl::*data;

// Вказівник на змінну-член

int (cl::*func)();

// Вказівник на функцію-член

22/54

c1

ob1(1), ob2(2);

//Створюємо об'єкти

c1

*p1,

*р2;

 

p1

=

&ob1;

// Доступ до об'єкта через вказівник

р2

=

&ob2;

 

data

= &c1::val;

// Визначаємо зсув змінної val

func

= &cl::double_val; // Визначаємо зсув функції double_val()

cout

<< "Значення: ";

 

cout

<<

pl->*data << " " << p2->*data << "\n";

cout

<< "Подвоєні значення: ";

cout

<<

(pl->*func)() << " ";

cout

<<

(p2->*func)() << "\n";

return 0;

}

У цьому варіанті програми змінні p1 і р2 є вказівниками на об'єкти класу c1, тому для доступу до членів val і double_func () застосовується оператор

"->*".

Запам'ятайте, що вказівники на члени відрізняються від вказівників на конкретні елементи об'єкта.

23/54

Розглянемо фрагмент програми, вважаючи, що клас c1 оголошений, як вказано вище.

int cl::*d; int *p;

c1 o;

p

=

&o.val;

// Адреса конкретної змінної val

d

=

&cl::val;

// Зсув узагальненої змінної val

Тут вказівник р посилається на цілочисельну змінну, яка належить конкретному об'єкту. У той же час змінна d зберігає зсув члена val всередині будь-якого об'єкта класу cl.

Як правило, оператори, пов'язані з вказівниками на члени класу, застосовуються виняткових ситуаціях. У повсякденному програмуванні вони звичайно не використовуються.

24/54

Посилання

У мові C++ є змінні, які дуже нагадують вказівники. Вони називаються посиланнями (reference). По суті, посилання - це неявний вказівник. Вони використовуються: для передачі параметрів функції, для повернення значення функції й у якості самостійних змінних. Розглянемо кожний із цих варіантів.

Передача параметрів за допомогою посилань

Імовірно, найважливіше застосування посилань полягає в створенні функцій, які автоматично передбачають передачу параметрів по посиланню. Як відомо, аргументи передаються функції двома способами: за значенням і по посиланню. Якщо аргумент передається за значенням, функція одержує його копію.

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

Щоб усвідомити, наскільки важливою є ця можливість, розглянемо механізм передачі параметрів по посиланню за допомогою вказівників. Наступна програм явно створює вказівник на аргумент функції neg(), призначеної для зміни знаку цілочисельної змінної.

25/54

// Аргумент передається по посиланню за допомогою явного вказівника.

#include <iostream> using namespace std; void neg(int *i);

int main()

 

{

 

 

int x;

 

 

x = 10;

 

є від’ємним по віднош. до даного числа ";

cout << x << "

neg(&x);

x <<

"\n";

cout <<

return

0;

 

}

 

*i)

void neg(int

{

 

 

*i = -*i;

 

}

 

 

У даній програмі функція neg() одержує як параметр вказівник на цілочисельну змінну, знак якої потрібно змінити на протилежний Отже, функція neg() повинна явно одержувати адресу змінної х. Крім того, щоб одержати доступ до змінної, на яку посилається вказівник i усередині функції neg(), необхідно застосовувати оператор "*".

26/54

Ось як влаштований механізм передачі аргументів по посиланню в мові C++, причому в мові C цей спосіб є єдиним. На щастя, у мові C++ існує можливість автоматизувати цей механізм, використовуючи параметри, що є посиланнями.

Щоб створити посилання на параметр, перед його ім'ям варто ставити символ &. Наприклад, оголошується посилання на аргумент i функції neg().

void neg(int &i);

У цьому випадку ім'я i стає другим ім'ям аргументу функції neg(), і будь-які операції над нею автоматично поширюються на фактичний аргумент. З технічної точки зору змінна i є неявним вказівником на аргумент функції. Тепер оператор "*" стає зайвим. Крім того, тепер необов'язково ставити перед ім'ям аргументу символ &. Розглянемо нову версію програми.

// Застосування посилання на аргумент.

#include <iostream> using namespace std;

void neg(int &i); // Змінна i стала посиланням int main{)

{ int x;

27/54

x = 10;

cout << x << " є від’ємним по віднош. до даного числа "; neg(x); // Оператор & більше не потрібний cout << х << "\n";

return 0;

}

void neg(int &i)

{

i = -i; // Змінна i є посиланням, оператор * більше не потрібний

}

Посилання на параметр автоматично (неявно) встановлюються на аргумент функції. Отже, у попередній програмі оператор

i = -i;

насправді працює зі змінною х, а не з її копією. Оператор & стає непотрібним. Крім того, всередині функції параметр, переданий за допомогою посилання, використовується безпосередньо, без застосування оператора "*". Як правило, значення, присвоєне посиланню, насправді присвоюється змінній, до якої це посилання відноситься.

28/54

Всередині функції посилання на параметр неможливо зв'язати з іншою змінною. Інакше кажучи, оператор

i++;

всередині функції neg() збільшує значення параметра, а не переміщає вказівник i на нову адресу.

Розглянемо ще один класичний приклад. Ця програма використовує посилання на параметри для їхньої перестановки усередині функції swap().

include <iostream> using namespace std;

void swap(int &i, int &j); int main()

{

int a, b, c, d;

a = 1; b = 2; c = 3; d = 4;

cout << "а i b: " << a << " " << b << "\n"; swap(a, b); // Оператор & не потрібний

cout << "а i b: " << a << " " << b << "\n"; cout << "с i d: " << c << " " << d << "\n"; swap(c, d) ;

29/54

cout << "с i d: " << c << " " << d << "\n"; return 0; }

void swap(int &i, int &j)

{

 

int t;

// Оператор * не потрібний

t = i;

i = j;

 

j = t;

 

}

 

У результаті роботи цієї програми на екран будуть видані наступні рядки.

a i b:

1

2

а i b:

2

1

с

і d:

3

4

с

і d:

4

3

Передача посилань на об'єкти

Відомо, що при передачі об'єкта як параметра функції створюється його копія. По завершенні роботи функції викликається деструктор копії. Однак, якщо параметр викликається по посиланню, копія об'єкта не створюється. Це значить, що після повернення управління параметр функції не знищується й деструктор не викликається. Розглянемо наступний приклад.

30/54

Соседние файлы в папке ТА_Методички