Освой самостоятельно С++ за 21 день.
Шрифт:
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.
В
Поскольку тип массива был объявлен как 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 второму объекту массива.
Указатель на массив или массив указателей
Рассмотрим следующие три объявления:
1: Cat Family0ne[500];
2: CAT >> FamilyTwo[500];
3: CAT * FamilyThree = new CAT[500];
В
первом случае объявляется массив FamilyOne, содержащий 500 объектов типа CAT. Во втором случае — массив FamilyTwo, содержащий 500 указателей на объекты класса CAT, и в третьем случае — указатель FamilyThree, ссылающийся на массив из 500 объектов класса CAT.В зависимости от того, какое объявление используется в программе, принципиально меняются способы управления массивом. Как ни странно, но указатель FamilyThree по сути своей гораздо ближе к массиву FamilyOne, но принципиально отличается от массива указателей FamilyTwo.
Чтобы разобраться в этом, следует внимательно рассмотреть, что содержат в себе все эти переменные. Указатель на массив FamilyThree содержит адрес первого элемента массива, но ведь это именно то, что содержит имя массива FamilyOne.
Имена массивов и указателей
В C++ имя массива представляет собой константный указатель на первый элемент массива. Другими словами, в объявлении
CAT Family[50];
создается указатель Family на адрес первого элемента массива &Family[0].
В программе допускается использование имен массивов как константных указателей и наоборот. Таким образом, выражению Family + 4 соответствует обращение к пятому элементу массива Family[4].
Компилятор выполняет с именами массивов те же математические действия сложения, инкремента и декремента, что и с указателями. В результате операция Family + 4 будет означать не прибавление четырех байтов к текущему адресу, а сдвиг на четыре объекта. Если размер одного объекта равен четырем байтам, то к адресу в имени массива будут добавлены не 4, а 16 байт. Если в нашем примере каждый объект класса CAT содержит четыре переменные-члена типа long по четыре байта каждая и две переменные-члена типа short по два байта каждая, то размер одного элемента массива будет равен 20 байт и операция Family + 4 сдвинет адрес в имени указателя на 80 байт.
Объявление массива в динамической области памяти и его использование показано в листинге 12.7.
Листинг 12.7. Создание массива с использованием ключевого слова new
1: // Листинг 12.7. Массив в динамической области памяти
2:
3: #include <iostream.h>
4:
5: class CAT
6: {
7: public:
8: CAT { itsAge = 1; itsWeight=5; }
9: ~CAT;
10: int GetAge const { return itsAge; }
11: int GetWeight const { return itsWeight; }
12: void SetAge(int age) { itsAge = age; }
13:
14: private:
15: int itsAgo;
16: int itsWeight;
17: };
18:
19: CAT::~CAT
20: {
21: // cout << "Destructor called!\n";
22: }
23:
24: int main
25: {
26: CAT * Family = new CAT[500];
27: int i;
28:
29: for (i = 0; i < 500; i++)
30: {
31: Family[i].SetAge(2*i +1);
32: }