Шаг 15 - Как сделать массив из чего угодно.
Шаг 15 - Как сделать массив из чего угодно.
Массивы и оператор operator[].
Давайте попробуем придумать класс, объекты которого вели бы себя как массивы? Поехали. Решим, что класс внутри себя должен иметь для простоты массив, ну там счетчик элементов… вроде больше нечему там быть. Ну раз так, то возьмем стек из Шага 13, для чистоты эксперимента выкинем спорные перегрузки operator+, operator+= и operator-, а для доступа к элементу пишем функцию int getat (int). Но что получается? Значит, добавление-изъятие мы пишем как функции только ради чистоты стиля, а других мотивов нет? А с доступом к элементу нам вообще ничего не мешает - пусть вместо getat() будет operator[](), а возвращает ссылку - ссылке же можно присвоить значение, а значит, работать будет в обе стороны, и на чтение и на запись!
class CArray {
private:
int a[100];
int iTop;
public:
// Тут смотреть нечего, конструкторы да присваивания, банально
CArray ():iTop(0) {}
CArray (const CArray& _ca) {
iTop = _ca.iTop;
for (int i=0; i++; i ‹100) a[i]= _ca.a[i];
}
CArray& operator=(const CArray& _ca) {
if (this==&_ca) return *this;
for (int i=0; i++; i ‹100) a[i]= _ca.a[i];
iTop = _ca.iTop;
return *this;
}
CArray& add (int _i) {a[iTop]=_i; iTop++; return *this;}
int pop(void) {iTop-; return a[iTop+1];}
// Две функции доступа к элементам массива
int& getat (int _i){return a[_i];}
int& operator[](int _i){return a[_i];}
};
// проверим наши рассуждения
CArray c;
int main() {
c.add(1);
c.add(2);
c.add(3);
c.add(4);
c.add(5);
c.getat(3) = 10;
c[2]=20;
return 1;
}
Разумеется, я пропустил ВСЕ детали, и важные и мелкие, но это не главное. Самое главное - последние две функции декларации.
Надеюсь, Вы понимаете значение сделанного? Вы снова Властелин. Allmighty God. А как же? Вы полностью контролируете все и всех. Как назвать того, кто издает законы, по которым живут все без исключения? Творения которого рождаются и умирают лишь по воле его? Нарушившего закон его постигает немедленная и неотвратимая кара? (Да-да, именно, как у Буча там: "сервер, не выполняющий… инварианты Господа нашего…" ой нет, не было такого, но он имел в виду!)
Практически Вы можете проверять значение индекса не меньше 0 и не больше iTop. Можете вместо массива положить указатель на массив int** a, тогда в operator[] возвращать нужно не int& а int*& - а вести себя будет точно так же. Можете вообще читать с диска или с бараньей лопатки. Более того (и это кстати очень важно) перегрузить operator[] не только для int но и чего угодно другого: для строки, float и всего остального, и не один раз. Есть ограничение правда - аргумент может быть только один. Ха, смешные потуги жалкого компилятора, нас уже не остановить:
// Это класс, объединяющий пару аргументов
class pair {
public:
int x; int y;
pair(int _x=0, int _y=0):x(_x), y(_y)р {}
};
// Перегруженный operator[]
int& operator[](pair);
//использование.
OurArray[pair(1,2)].OurFunction();
Тормознем немного. Королева в восхищении, но… есть немного проблем.