QT 4: программирование GUI на С++ - [186]

Шрифт
Интервал

или ->.

• Ссылка не может быть нулевой.

Ссылки в основном используются при объявлении параметров. По умолчанию в С++ используется передача параметров по значению, т.е. при передаче параметров функции последняя получает в действительности новую копию объекта. Ниже приводится определение функции, которая получает параметры, передаваемые по значению.

>#include

>using namespace std;

>double manhattanDistance(Point2D a, Point2D b)

>{

> return abs(b.x() - a.x()) + abs(b.y() - a.y());

>}

Эта функция может вызываться следующим образом:

>Point2D harlem(77.5, 50.0);

>Point2D broadway(12.5, 40.0);

>double distance = manhattanDistance(broadway, harlem);

Опытные С—программисты избегают операций копирования путем объявления параметров в виде указателей вместо значений:

>double manhattanDistance(const Point2D *ap, const Point2D *bp)

>{

> return abs(bp->x() - ap->x()) + abs(bp->y() - ap->y());

>}

После этого при вызове функции должны передаваться адреса вместо значений:

>Point2D harlem(77.5, 50.0);

>Point2D broadway(12.5, 40.0);

>double distance = manhattanDistance(&broadway, &harlem);

Ссылки введены в С++ для того, чтобы сделать синтаксис менее громоздким и чтобы предотвратить передачу нулевого указателя. Если вместо указателей использовать ссылки, функция будет иметь следующий вид:

>double manhattanDistance(const Point2D &a, const Point2D &b)

>{

> return abs(b.x() - a.x()) + abs(b.y() - a.y());

>}

Ссылка объявляется аналогично указателю с использованием & вместо *. Однако при использовании ссылки можно забыть о том, что она является каким-то адресом памяти, и рассматривать ее как обычную переменную. Кроме того, вызов функции, принимающей ссылки в качестве аргументов, не требует специальной записи аргументов (не требуется задавать оператор &).

В конце концов, заменяя в списке параметров Point2D на const Point2D &, мы уменьшаем накладные расходы на вызов функции — вместо копирования 256 битов (размер четырех типов double) копируются только 64 или 128 бит, что зависит от размера указателя, принятого в целевой платформе.

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

>void transpose(Point2D &point)

>{

> double oldX = point.x();

> point.setX(point.y());

> point.setY(oldX);

>}

В некоторых случаях имеется ссылка и требуется вызвать функцию, которая принимает указатель и наоборот. Для преобразования ссылки в указатель можно просто использовать унарный оператор &:

>Point2D point;

>Point2D &ref = point;

>Point2D *ptr = &ref;

Для преобразования указателя в ссылку используется унарный оператор *:

>Point2D point;

>Point2D *ptr = &point;

>Point2D &ref = *ptr;

Ссылки и указатели представляются в памяти одинаково и часто могут использоваться вместо друг друга, из-за чего возникает естественный вопрос о том, в каких случаях что из них следует предпочесть. С одной стороны, ссылки имеют более удобный синтаксис, с другой стороны — указатели в любой момент можно вновь устанавливать на указатель другого объекта, они могут содержать нулевое значение и более явный синтаксис их применения часто является неприятностью, неожиданно оказавшейся благом. По этим причинам предпочтение часто отдается указателям, а ссылки почти исключительно используются при объявлении параметров функций совместно с ключевым словом const.

Массивы

Массивы в С++ объявляются с указанием количества элементов массива в квадратных скобках после имени переменной массива. Допускаются двумерные массивы, т.е. массив массивов. Ниже приводится определение одномерного массива, содержащего 10 элементов типа int:

>int fibonacci[10];

Доступ к элементам осуществляется с помощью следующей записи: fibonacci[0], fibonacci[1], … fibonacci[9]. Часто требуется инициализировать массив при его определении:

>int fibonacci[10] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };

В таких случаях можно не указывать размер массива, поскольку компилятор может его рассчитать по количеству элементов в списке инициализации:

>int fibonacci[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };

Статическая инициализация также работает для сложных типов, например для Point2D:

>Point2D triangle[] = {

> Point2D(0.0, 0.0), Point2D(1.0, 0.0), Point2D(0.5, 0.866)

>};

Если не предполагается в дальнейшем изменять массив, его можно сделать константным:

>const int fibonacci[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };

Для нахождения количества элементов в массиве можно использовать оператор sizeof():

>int n = sizeof(fibonacci) / sizeof(fibonacci[0]);

Оператор sizeof() возвращает размер аргумента в байтах. Количество элементов массива равно его размеру в байтах, поделенному на размер одного его элемента. Поскольку это долго вводить, распространенной альтернативой является объявление константы и ее использование при определении массива:

>enum { NFibonacci = 10 };

>const int fibonacci[NFibonacci] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };

Есть соблазн объявить константу как переменную типа const int.


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.