Перегрузка оператора индексирования элементов массива [ ]
Содержание
- 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.
В программе подсчитывается количество вхождений символов латинского алфавита ‘а’..’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. Перегрузка оператора присваивания =. Примеры
⇑