Освой самостоятельно С++ за 21 день.
Шрифт:
В этой книге рассматриваются только некоторые дополнительные средства программирования, такие как массивы указателей, массивы с резервированием памяти в области динамического обмена и ряд других возможностей. Больше информации о средствах программирования, открывающих дополнительные возможности, можно прочитать в моей книге C++ Unleashed, выпущенной издательством Sams Publishing. И вообще, всегда следует помнить, что каким бы хорошим программистом вы ни были, всегда остается то, чему следовало бы научиться,
Массивы указателей
Все массивы, рассмотренные нами до сих пор, хранили значения своих элементов в стеках памяти. Использование стековой памяти связано с рядом ограничений, которых можно избежать, если обратиться к более гибкой области динамической памяти. Это можно сделать, если сначала сохранить все объекты массива в области динамической памяти, а затем собрать в массиве указатели на эти объекты. Этот подход значительно сократит потребление программой стековой памяти компьютера. В листинге 12.6 показан тот же массив, с которым мы работали в листинге 12.4, но теперь все его объекты сохранены в области динамической памяти. Чтобы показать возросшую эффективность использования памяти программой, в этом примере размер массива был увеличен с 5 до 500 и его название изменено с Litter (помет) на Family (семья).
Листинг 12.6. Сохранение массива в области динамической памяти
1: // Листинг 12.6. Массив указателей на обьекты 2:
3: #include <iostream.h>
4:
5: class CAT
6: {
7: public:
8: CAT { itsAge = 1; itsWeight=5; }
9: ~CAT { } // destructor
10: int GetAge const { return itsAge; }
11: int GetWeight const { return itsWeight: }
12: void SetAge(int age) ( itsAge = age; }
13:
14: private:
15: int itsAge;
16: int itsWeight;
17: };
18:
19: int main
20: {
21: CAT * Family[500];
22: int i;
23: CAT * pCat;
24: for (i = 0; i < 500; i++)
25: {
26: pCat = new CAT;
27: pCat->SetAge(2*i +1);
28: Family[i] = pCat;
29: }
30:
31: for (i = 0; i < 500; i++)
32: {
33: cout << "Cat #" << i+1 << ": ";
34: cout << Family[i]->GetAge << endl;
35: }
36: return 0;
37: }
Результат:
Cat #1: 1
Cat #2: 3
Cat #3: 5
...
Cat #499: 997
Cat #500: 999
Анализ: Объявление класса CAT в строках 5—17 идентично объявлению этого клас- • ca в листинге 12.4. Но, в отличие от предыдущего листинга, в строке 21
объявляется массив Family, в котором можно сохранить 500 указателей на объекты класса CAT.
В цикле инициализации (строки 24-29) в области динамической памяти создается 500 новых объектов класса CAT, каждому из которых присваивается значение переменной itsAge, равное удвоенному значению индекса плюс один. Таким образом, первому объекту класса CAT присваивается значение 1, второму — 3, третьему — 5 и т.д. В этом же цикле каждому элементу массива присваивается указатель на вновь созданный объект.
Поскольку тип массива был объявлен как CAT*, в нем сохраняются именно указатели, а не их разыменованные значения.
Следующий цикл (строки 31—35) выводит на экран все значения объектов, на которые делаются ссылки в массиве. Обращение к указателю выполняется с помощью индекса: Family[i]. После того как элемент массива установлен, следует вызов метода GetAge.
В данном примере программы все элементы массива сохраняются в стековой памяти. Но в этот раз элементами являются указатели, тогда как сами объекты хранятся в области динамического обмена.
Объявление массивов в области динамического обмена
Существует возможность поместить весь массив в область динамического обмена. Для этого используется ключевое слово new и оператор индексирования, как показано в следующем примере, где результатом этой операции является указатель на массив, сохраненный в области динамического обмена:
CAT *Family = new CAT[500];
Указатель Family будет содержать адрес в динамической области первого элемента массива из пятисот объектов класса CAT. Другими словами, в указателе представлен адрес объекта Family[0].
Еще одно преимущество подобного объявления массива состоит в том, что в программе с переменной Family теперь можно будет выполнять математические действия как с любым другим указателем, что открывает дополнительные возможности в управлении доступом к элементам массива. Например, можно выполнить следующие действия:
CAT *Family = new CAT[500];
CAT *pCat = Family; // pCat указывает на Family[0]
pCat->SetAge(10); // присваивает Family[0] значение 10
pCat++; // переход к Family[1]
pCat->SetAge(20); // присваивает Family[1] значение 20
В данном примере объявляется новый массив из 500 объектов класса CAT и возвращается указатель на первый элемент этого массива. Затем, используя это указатель и метод SetAge, объявленный в классе CAT, первому объекту массива присваивается
значение 10. Переход к следующему объекту массива осуществляется за счет приращения адреса в указателе на массив, после чего тем же способом присваивается значение 20 второму объекту массива.