Перевантаження оператору індексування елементів масиву [ ]
Зміст
- 1. Які обмеження накладаються на перевантаження оператору [ ]?
- 2. Перевантаження оператора індексування елементів масиву [ ]. Особливості використання
- 3. Варіанти реалізації операторної функції operator[]() в класі. Загальна форма
- 4. Приклади перевантаження оператора індексування елементів масиву [ ]
- 5. Які вимоги до параметру операторної функції operator[]()?
- 6. Приклад класу, що містить операторну функцію operator[](), індекс якої є тип char
- Зв’язані теми
Пошук на інших ресурсах:
1. Які обмеження накладаються на перевантаження оператору [ ]?
На перевантаження оператору [] накладаються наступні обмеження:
- до цього оператора заборонено застосовувати “дружні” функції;
- операторна функція, що перевантажують цей оператор, має бути нестатичною функцією-членом.
⇑
2. Перевантаження оператора індексування елементів масиву [ ]. Особливості використання
У мові програмування C++ є можливість перевантажувати оператор індексування елементів масиву [ ]. Цей оператор вважається унарним, тобто потребує одного параметра — індексу масиву. Отже, доцільно перевантажувати оператор [ ] в класах, де використовуються масиви.
Якщо у класі, що реалізує масив, перевантажено оператор [ ], то об’єкт цього класу можна використовувати як звичайний масив (з використанням доступу за індексом), що є дуже зручно і природньо.
Наприклад. Нехай задано клас з іменем A. У класі перевантажено оператор індексування масиву [ ]. Тоді використання екземпляру класу A може бути таким:
obj[d]
де
- obj – екземпляр (об’єкт) класу A;
- d – індекс. Це є параметр, що передається операторній operator[]() функції класу A.
У вищенаведеному прикладі виклик
obj[d]
перетворюється на виклик
obj.operator[](d)
⇑
3. Варіанти реалізації операторної функції operator[]() в класі. Загальна форма
Для того, щоб перевантажити оператор індексування елементів масиву [], в класі повинна бути реалізована операторна функція operator[](). Існує 2 варіанти реалізації операторної функції operator[](). Ці варіанти відрізняються поверненням значення з операторної функції. Операторна функція отримує один параметр, який є індексом масиву.
Варіант 1. Цей варіант застосовується, якщо оператор [ ] має бути використаний у правій (і тільки у правій) частині оператора присвоювання. Тобто значення елементу масиву в класі не змінюється.
У цьому випадку операторна функція operator[]() повертає значення деякого типу. Загальна форма функції при її реалізації в класі
class ClassName { // ... // операторна функція повертає значення типу type type operator[](int d) { // ... } };
Після цього, можна використовувати екземпляр класу ClassName наступним чином:
x = obj[3];
де
- x – деяка змінна типу type;
- obj – екземпляр (об’єкт) класу ClassName.
Варіант 2. Цей варіант застосовується у випадку, коли потрібно щоб оператор [] розміщувався у лівій та правій частині оператора присвоювання. Наявність оператора індексування [] у лівій частині оператора присвоювання означає, що в об’єкті класу можна змінювати значення елементу масиву за індексом.
Відмінність від попереднього варіанту (Варіант 1) полягає у тому, що функція повертає посилання & на тип. Загальна форма оголошення операторної функції наступна
class ClassName { // ... // операторна функція повертає посилання (&) на тип type type& operator[](int d) { // ... } };
Після такого оголошення можна використовувати екземпляр класу ClassName наступним чином:
// використання оператора [] для об’єкту класу x = obj[3]; // у правій частині оператора присвоювання obj[5] = y; // у лівій частині оператора присвоювання
де
- x – деяка змінна типу type;
- obj – екземпляр (об’єкт) класу ClassName.
⇑
4. Приклади перевантаження оператора індексування елементів масиву []
Приклад 1. Приклад перевантаження оператора [] у класі. Клас реалізує масив чисел типу int. Максимальна кількість елементів масиву рівна 10. Операторна функція класу повертає посилання на тип int. Це означає, що оператор [] можна використовувати у лівій частині оператора присвоювання.
У класі Array10 оголошуються:
- A – внутрішній масив 10 цілих чисел;
- n – кількість елементів у масиві;
- конструктори класу;
- метод GetN(). Цей метод призначений для читання значення n;
- методи SetAi() та GetAi() для доступу до елементів масиву A;
- операторна функція operator[](). Ця функція перевантажує оператор доступу до елементу масиву за його індексом.
Текст програми наступний:
#include <iostream> using namespace std; // клас, що реалізує масив з 10 цілих чисел class Array10 { private: int A[10]; // масив int n; // к-сть елементів у масиві public: // конструктори класу // конструктор без параметрів Array10() { n = 0; } // конструктор з 1 параметром Array10(int _n) { if ((_n >= 0) && (_n <= 10)) { n = _n; for (int i = 0; i < n; i++) A[i] = 0; // занулити масив } else n = 0; } // методи доступу до елементів масиву // зчитати к-сть елементів масиву int GetN() { return n; } // записати в елемент масиву значення void SetAi(int index, int item) { if ((index>=0)&&(index<10)) A[index] = item; } // зчитати значення по індексу // внутрішній метод int GetAi(int index) { return A[index]; } // перевантаження оператора [] отримання елемента масиву // операторна функція, реалізована всередині класу int& operator[](int index) { return A[index]; } }; void main() { // оператор індексування масиву [] Array10 A1(10); // сформувати масив A1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] for (int i = 1; i <= 10; i++) A1[i - 1] = i; // виклик операторної функції operator[]() класу Array10 // перевірка int t; t = A1[3]; // виклик операторної функції, t = 4 // Оператор [] у лівій частині оператора присвоювання A1[5] = 205; t = A1.GetAi(5); // t = 205 cout << "t = " << t << endl; }
Як видно з прикладу, операторна функція повертає посилання на тип int
// операторна функція - повертає int& int& operator[](int index) { return A[index]; }
Це означає, що оператор [ ] можна використовувати у лівій частині оператора присвоювання
...
// Оператор [] у лівій частині оператора присвоювання
A1[5] = 205;
...
Якщо операторну функцію реалізувати так, що вона повертає значення int (а не посилання int&)
// операторна функція - повертає int int operator[](int index) { return A[index]; }
то використовувати оператор [ ] у лівій частині оператора присвоювання буде заборонено
... // Оператор [] у лівій частині оператора присвоювання A1[5] = 205; // помилка, заборонено! t = A1[3]; // так добре, можна ...
Приклад 2. Перевантаження оператора індексування елементів масиву [ ] для масиву структур типу BOOK.
У прикладі оголошуються:
- структура типу BOOK, що містить інформацію про книгу;
- клас ArrayBooks, який реалізує динамічний масив книг типу BOOK.
У класі ArrayBooks реалізовано:
- внутрішню змінну-покажчик на тип BOOK;
- внутрішню змінну n, яка визначає кількість книг у масиві;
- два конструктори;
- метод GetN(), який повертає кількість книг n у масиві;
- операторна функція operator[](). З допомогою цієї функції здійснюється доступ до заданого елементу масиву. Функція перевантажує оператор доступу за індексом [].
Текст програми, створеної за шаблоном Console Application наступний:
#include <iostream> #include <stdio.h> using namespace std; // структура, що описує книгу struct BOOK { string title; // назва книги int year; // рік видання float price; // вартість книги }; // клас, що реалізує масив книг типу BOOK // містить перевантажену операторну функцію operator[]() class ArrayBooks { private: BOOK * B; // пам'ять для масиву виділяється динамічно int n; // кількість книг public: // конструктори класу ArrayBooks() { n = 0; B = NULL; } ArrayBooks(int _n) { n = _n; // виділити пам'ять для покажчиків на BOOK B = (BOOK*) new BOOK[n]; // заповнити кожну книгу пустими значеннями for (int i=0; i<n; i++) { B[i].title = ""; B[i].price = 0.00; B[i].year = 0; } } // деструктор ~ArrayBooks() { // звільнити пам'ять, виділену під масив структур if (n>0) delete[] B; } // метод, що повертає значення n int GetN(void) { return n; } // операторна функція, яка перевантажує оператор індексування [] // функція повертає BOOK&, для того щоб оператор [] можна було використовувати // в лівій частині оператора присвоювання BOOK& operator[](int index) { if ((index>=0)&&(index<n)) return B[index]; else { // повернути пусту структуру BOOK BB; BB.title = ""; BB.price = 0.0; BB.year = 0; return BB; } } }; void main() { // демонстрація перевантаження оператора [] ArrayBooks AB(3); // створити об'єкт класу ArrayBooks, у масиві 3 елементи // виклик операторної функції operator[](), сформувати значення // книга - 1 AB[0].title = "This is a first book"; AB[0].price = 99.99; AB[0].year = 2999; // книга - 2 AB[1].title = "This is a second book"; AB[1].price = 125.95; AB[1].year = 2020; // книга - 3 AB[2].title = "Third book"; AB[2].price = 777.77; AB[2].year = 2000; // перевірка string title; double price; int year; title = AB[1].title; // title = "This is a second book" price = AB[1].price; // price = 125.95 year = AB[1].year; // year = 2020 // вивести на екран cout << "Title = " << title.c_str() << ::endl; cout << "Price = " << price << ::endl; cout << "Year = " << year << ::endl; }
Результат виконання програми
Title = This is a second book Price = 125.95 Year = 2020
⇑
5. Які вимоги до параметру операторної функції operator[]()?
Операторна функція, яка перевантажує оператор індексування елементів масиву, отримує параметр, який є індексом в масиві. Тип параметру не обов’язково має бути int. Допускається інший тип параметру в індексі масиву (наприклад, char).
⇑
6. Приклад класу, що містить операторну функцію operator[](), індекс якої є тип char
Цей приклад демонструє твердження, що тип індексу в операторній функції може бути не тільки int.
У прикладі реалізовано клас CharIndex, який містить масив з 26 елементів. У класі оголошується операторна функція operator[](), яка в якості індексу отримує значення типу char.
У програмі підраховується кількість входжень символів латинського алфавіту ‘a’..’z’ в заданому тексті.
Текст програми, створеної за шаблоном Console Application, наступний
#include <iostream> using namespace std; // доступ за індексом в операторній функції - клас CharIndex class CharIndex { private: int A[26]; // масив частоти входжень символу в тексті public: CharIndex() { for (int i=0; i<26; i++) A[i] = 0; } // операторна функція - доступ за типом char int& operator[](char c) { int position; // позиція в масиві A position = (int)c - int('a'); return A[position]; } }; void main(void) { // демонстрація твердження, // що тип індексу не обов'язково має бути int CharIndex cI; // об'єкт класу CharIndex string text; // заданий текст int i; char sym; // задано деякий текст text = "C++ is the best language in the world!"; // обчислити кількість входжень символів 'a'..'z' у тексті for (i = 0; i<text.length(); i++) cI[text[i]]++; // виклик операторної функції // вивід, виводяться тільки ненульові значення for (i=0; i<26; i++) { sym = 'a' + i; // взяти індекс if (cI[sym]>0) cout << sym << " = " << cI[sym] << ::endl; } }
Результат виконання програми
a = 2 b = 1 d = 1 e = 4 g = 2 h = 2 i = 2 l = 2 n = 2 o = 1 r = 1 s = 2 t = 3 u = 1 w = 1
⇑
Зв’язані теми
- 1. Перевантаження операторів у C++. Операторна функція. Ключове слово operator. Перевантаження арифметичних операторів +, –, *, /. Приклади реалізації вбудованих операторних функцій
- 2. “Дружні” операторні функції: відмінності, реалізація особливості застосування. Перевантаженняоператорів +, –, *, / з допомогою “дружніх” операторних функцій
- 3. Перевантаження інкрементних та декрементних операторів ++, ––. Приклади
- 4. Перевантаження скорочених операторів присвоювання +=, -=, *=, /=, %=. Приклади
- 5. Перевантаження операторів new та delete. Приклади
- 6. Перевантаження оператору присвоювання =. Приклади
⇑