Для локальных переменных, являющихся объектами класса, доступ к членам класса осуществляется с помощью оператора прямого доступа (.). Для экземпляров класса, созданных динамически, оператор прямого доступа применяется для объектов, полученных разыменованием указателя. Например, для вызова функции-члена GetAge нужно написать:
(*pRags).GetAge();
Скобки указывают на то, что оператор разыменования должен выполняться еще до вызова функции GetAge().
Такая конструкция может оказаться достаточно громоздкой. Решить эту проблему позволяет специальный оператор косвенного обращения к члену класса, по написанию напоминающий стрелку (->). Для набора этого оператора используется непрерывная последовательность двух символов: тире и знака "больше". В C++ эти символы рассматриваются как один оператор. Листинг 8.6 иллюстрирует пример обращения к переменным и функциям класса, экземпляр которого размещен в области динамического обмена.
Листинг 8.6. Доступ к данным объекта в области динамического обмена
1: // Листинг 8.6.
2: // Доступ к данным объекта в области динамического обмена
3:
4: #include
5:
6: class SimpleCat
7: {
8: public:
9: SimpleCat() { itsAge = 2; }
10: ~SimpleCat() { }
11: int GetAge() const { return itsAge; >
12: void SetAge(int age) { itsAge = age; }
13: private:
14: int itsAge;
15: };
16:
17: int main()
18: {
19: SimpleCat * Frisky = new SimpleCat;
20: cout << "Frisky " << Frisky->GetAge() << " years old\n";
21: Frisky->SetAge(5);
22: cout << "Frisky " << Frisky->GetAge() << " years old\n";
23: delete Frisky;
24: return 0;
25: }
Результат:
Frisky 2 years old
Frisky 5 years old
Анализ:В строке 19 в области динамического обмена выделяется память для хранения экземпляра класса SimpleCat. Конструктор, вызываемый по умолчанию, присваивает новому объекту возраст два года. Это значение получено как результат выполнения функции-члена GetAge(), которая вызывается в строке 20. Поскольку мы имеем дело с указателем на объект, для вызова функции используется оператор косвенного обращения к члену класса (->). В строке 21 для установки нового значения возраста вызывается метод SetAge(), а повторный вызов функции GetAge() (строка 22) позволяет получить это значение.
Динамическое размещение членов класса
В качестве членов класса могут выступать и указатели на объекты, размещенные в области динамического обмена. В таких случаях выделение памяти для хранения этих объектов осуществляется в конструкторе или в одном из методов класса. Освобождение памяти происходит, как правило, в деструкторе (листинг 8.7.).
Листинг 8.7. Указатели как члены класса
1: // Листинг 8.7.
2: // Указатели как члены класса
3:
4: #include
5:
6: class SimpleCat
7: {
8: public:
9: SimpleCat();
10: ~SimpleCat();
11: int GetAge() const { return *itsAge; }
12: void SetAge(int age) { *itsAge = age; }
13:
14: int GetWeight() const { return *itsWeight; }
15: void setWeight (int weight) { *itsWeight = weight; }
16:
17: private:
18: int * itsAge:
19: int * itsWeight;
20: };
21:
22: SimpleCat::SimpleCat()
23: {
24: itsAge = new int(2);
25: itsWeight = new int(5);
26: }
27:
28: SimpleCat::~SimpleCat()
29: {
30: delete itsAge;
31: delete itsWeight;
32: }
33:
34: int main()
35: {
36: SimpleCat *Frisky = new SimpleCat;
37: cout << "Frisky " << Frisky->GetAge() << " years old\n";
38: Frisky->SetAge(5);
39: cout << "Frisky " << Frisky->GetAge() << " years old\n";
40: delete Frisky;
41: return 0;
42: }
Результат:
Frisky 2 years old
Frisky 5 years old
Анализ:Объявляем класс, переменными-членами которого являются два указателя на тип int. В конструкторе класса (строки 22—26) выделяется память для хранения этих переменных, а затем им присваиваются начальные значения.
Выделенная под переменные-члены память освобождается в деструкторе (строки 28—32). После освобождения памяти в деструкторе присваивать указателям нулевые значения не имеет смысла, поскольку уничтожается и сам экземпляр класса. Такая ситуация является одним из тех случаев, когда после освобождения памяти указателю можно не присваивать значение 0.
При выполнении функции, из которой осуществляется обращение к переменным класса (в данном случае main()), вы можете и не знать, каким образом выполняется это обращение. Вы лишь вызываете соответствующие методы класса (GetAge() и SetAge()), а все операции с памятью выполняются внутренними механизмами класса.
При уничтожении объекта Frisky (строка 40) вызывается деструктор класса SimpleCat. В деструкторе память, выделенная под члены класса, освобождается. Если один из членов класса является объектом другого определенного пользователем класса, происходит вызов деструктора этого класса.
Читать дальше