04 Point2D alpha;

05 Point2D beta;

06 Point2D *ptr;

07 ptr = α

08 ptr->setX(1.0);

09 ptr->setY(2.5);

10 ptr = β

11 ptr->setX(4.0);

12 ptr->setY(4.5);

13 ptr = 0;

14 return 0;

15 }

В этом примере используется класс Point2D из предыдущего подраздела. В строках 4 и 5 определяется два объекта типа Point2D. Эти объекты инициализируются в значение (0, 0) стандартным конструктором Point2D.

В строке 6 определяется указатель на объект Point2D. Для обозначения указателя здесь используется звездочка перед именем переменной. Поскольку мы не инициализируем указатель, он будет содержать произвольный адрес памяти. Эта ситуация изменяется в строке 7, в которой адрес alpha присваивается этому указателю. Унарный оператор & возвращает адрес памяти, где располагается объект. Адрес обычно представляет собой 32-битовое или 64-битовое целое число, задающее смещение объекта в памяти.

В строках 8 и 9 мы обращаемся к объекту alpha с помощью указателя ptr. Поскольку ptr является указателем, а не объектом, необходимо использовать оператор -> (стрелка) вместо оператора . (точка).

В строке 10 указателю присваивается адрес beta. С этого момента любая выполняемая нами операция с этим указателем будет воздействовать на объект beta.

В строке 13 указатель устанавливается в нулевое значение. С++ не имеет ключевого слова для представления указателя, который не ссылается ни на один объект; вместо этого мы используем значение 0 (или символическую константу NULL, которая разворачивается в 0). Попытка применения нулевого указателя приведет к краху приложения с выводом такого сообщения об ошибке, как «Segmentation fault» (ошибка сегментации), «General protection fault» (общая ошибка защиты) или «Bus error» (ошибка шины). Применяя отладчик, можно найти строку программного кода, которая приводит к краху.

В конце функции объект alpha содержит пару координат (1.0, 2.5), а объект beta — (4.0,4.5).

Указатели часто используются для хранения объектов, память для которых выделяется динамически с помощью оператора new. Используя жаргон С++ можно сказать, что эти объекты распределяются в «куче», в то время как локальные переменные (т.е. переменные, определенные внутри функции) хранятся в «стеке».

Ниже приводится фрагмент программного кода, иллюстрирующий динамическое распределение памяти при помощи оператора new:

01 #include "point2d.h"

02 int main

03 {

04 Point2D *point = new Point2D;

05 point->setX(1.0);

06 point->setY(2.5);

07 delete point;

08 return 0;

09 }

Оператор new возвращает адрес памяти для нового распределенного объекта. Мы сохраняем адрес в переменной указателя и обращаемся к объекту через этот указатель. Поработав с объектом, мы возвращаем занимаемую им память, используя оператор delete. В отличие от Java и C#, сборщик мусора отсутствует в С++; динамически распределяемые объекты должны явно освобождать занимаемую ими память при помощи оператора delete, когда они становятся больше ненужными. В главе 2 описывается механизм родственных связей Qt, который значительно упрощает управление памятью в программах, написанных на С++.

Если не вызвать оператор delete, память остается занятой до тех пор, пока не завершится программа. Это не создаст никаких проблем в приведенном выше примере, потому что память выделяется только для одного объекта, однако в программе, в которой постоянно создаются новые объекты, это может привести к нехватке машинной памяти. После удаления объекта переменная указателя по-прежнему будет хранить адрес объекта. Такой указатель является «повисшим указателем» и не должен использоваться для обращения к объекту. Qt предоставляет «умный» указатель QPointer, который автоматически устанавливает себя в 0, если удаляется объект QObject, на который он ссылается.

В приведенном выше примере мы вызывали стандартный конструктор и функции setX и setY для инициализации объекта. Вместо этого можно было использовать конструктор с двумя параметрами:

Point2D *point = new Point2D(1.0, 2.5);

Кроме того, мы могли бы распределить объект в стеке следующим образом:

Point2D point;

point.setX(1.0);

point.setY(2.5);

Распределенные таким образом объекты автоматически освобождаются в конце блока, в котором они появляются.

Если мы не собираемся модифицировать объект при помощи указателя, можно объявить указатель как константный. Например:

const Point2D *ptr = new Point2D(1.0, 2.5);

double x = ptr->x;

double у = ptr->y;

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже