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

Масиви, вказівники і посилання. Оператори динамічного розподілу пам’яті

Лекція № 5

Масиви об’єктів Вказівники на об’єкти Вказівники на довільні типи Вказівники на члени класу Посилання

Динамічне виділення пам’яті

Ми вже вивчили вказівники й масиви, а також їхнє застосування до вбудованих типів даних. Тепер розглянемо їхню взаємодію з об'єктами. Крім того, обговоримо нове поняття посилання, тісно пов'язане з вказівником. На завершення ознайомимося з операторами динамічного розподілу пам'яті.

Масиви об'єктів

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

#include <iostream> using namespace std; class cl

{

int i; public:

void set_i(int j) { i=j; } int get_i() { return i; } int main()

{

cl ob[3];

2/54

int i;

for(i=0; i<3; i++) ob[i].set_i(i+l); for(i=0; i<3; i++)

cout << ob[i].get_i() << "\n"; return 0;

}

Ця програма виводить на екран числа 1, 2 і 3.

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

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

Ось як виглядає трохи змінена версія попередньої програми.

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

int i ; public:

c1(int j) { i=j; } // Конструктор

3/54

int get_i() { return i; } };

int main ()

{

cl ob[3] = {1, 2,

3};

// Список ініціалізації

int i;

cout << ob[i].get_i() << "\n";

for(i=0; i<3; i++)

return 0;

 

 

}

 

 

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

c1 ob[3] = { c1(1), c1(2), c1(3) };

Тут конструктор c1 викликається явно. Зрозуміло, коротка форма ініціалізації використовується частіше. В основі цього способу лежить можливість автоматичного перетворення типу, якщо конструктор має тільки один аргумент. Таким чином, скорочену форму ініціалізації можна використовувати, тільки якщо масив складається з об'єктів, конструктори яких мають лише один аргумент. Якщо конструктор об'єкта має кілька аргументів, варто застосовувати повну форму ініціалізації. Розглянемо приклад.

4/54

#include <iostream> using namespace std;

class cl { int h;

int i; public:

cl(int j, int k) {h=j; i=k;} // Конструктор із двома параметрами int get_i() {return i;}

int get_h() {return h;} };

int main

{

cl ob[3]=

{

C1(1,2), Ініціалізація c1(3,4),

c1(5,6)

};

int i;

5/54

for(i=0; i<3; i++)

{

cout << ob[i].get_h(); cout << ", ";

cout << ob[i].get_i() << "\n"; } return 0;

}

Тут конструктор масиву c1 має два аргументи. Отже, варто застосувати не скорочену, а повну форму ініціалізації.

Ініціалізовані й неініціалізовані масиви

Особлива ситуація виникає, коли необхідно створити як ініціалізовані так і неініціалізовані масиви об'єктів. Розглянемо наступний клас.

class cl { int i ; public:

cl(int j) { i=j; } // Конструктор int get_i() { return i; }

};

6/54

Тут у класі c1 визначений конструктор з одним параметром. Це значить, що будь-який масив такого типу повинен бути ініціалізований. Таким чином, масив не можна оголосити звичайним чином.

c1 a[9]; // Помилка, конструкторові необхідний список ініціалізації

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

class c1 { int i; public:

cl() {

i=0;

}

 

// Викликається для неініціалізованих масивів

cl(int

j) {

i=j; }

// Викликається для ініціалізованих масивів

int get_i()

{

return i; }

};

 

 

 

 

7/54

У такому варіанті програми допускаються наступні оператори.

c1

a1[3] =

{3, 5, 6};

//

Ініціалізований масив

c1

а2[34];

 

//

Неініціалізований масив

Вказівники на об'єкти

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

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

int i; public: c1(int j) { i=j; }

int get_i() { return i; } };

int main()

{

c1 ob(88), *p;

8/54

р = &ob;

// Одержуємо адресу об'єкта ob.

cout << p->get_i();

// для виклику функції get_i()

return 0;

// застосовується оператор ->

 

}

 

Як відомо, при збільшенні вказівника на одиницю він переміщається на наступний елемент того ж типу. Наприклад, цілочисельний вказівник буде посилатися на наступне ціле число. Як правило, адресна арифметика залежить від типу вказівника. (Інакше кажучи, вона залежить від типу даних, на який посилається вказівник.) Це правило стосується й вказівників на об'єкти. Наприклад, наступна програма використовує вказівник для доступу до всіх трьох елементам масиву ob.

#include <iostream> using namespace std;

class c1 { int i;

public:

cl() { i=0; } cl(int j) { i=j; }

int get_i() { return i; }

};

9/54

int main()

{

cl ob[3] = {1, 2, 3};

cl *p;

int

i;

p = ob;

// Встановити вказівник на перший елемент масиву.

for(i=0; i<3; i++)

{

 

cout << p->get_i() << "\n";

p++;

// Вказівник на наступний об'єкт.

}

 

return 0;

}

 

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

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

public: int i;

10/54

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