Структуры.
Структуры представляют собой сгруппированные типы, используемые для описания наборов данных. Этот подход позволяет управлять всем набором как единым модулем, при этом сохраняется возможность ссылаться на отдельные компоненты по именам. В языке C++ можно использовать структуру для описания нового типа данных, а также задавать операции для него. Другими словами, осуществимо управление сгруппированными данными почти так же, как встроенными типами, вроде int и float.
Можно присваивать имена переменным и передавать эти переменные в качестве аргументов функций, а также выполнять множество других операций, как будет показано ниже.
Программа 1.3. Интерфейс типа данных point.
Этот интерфейс описывает тип данных, состоящий из набора значений "пары чисел с плавающей точкой" и операции "вычисление расстояния между двумя точками".
struct point { float x; float у; };
float distance(point, point);
При обработке геометрических данных используется абстрактное понятие точки на плоскости. Следовательно, можно ввести строку
struct point { float x; float у; };
для указания, что имя point будет использоваться для ссылки на пары чисел с плавающей точкой. Например, выражение
struct point a, b;
объявляет две переменные этого типа. Можно ссылаться по имени на отдельные члены структуры. Например, операторы
а.х = 1.0; а.у = 1.0; Ь.х = 4.0; Ь.у = 5.0;
устанавливают значения переменных таким образом, что а представляет точку (1,1), a b — точку (4,5).
Кроме того, можно передавать структуры функциям как аргументы. Например, код
float distance(point a, point b)
{ float dx = a.x - b.x, dy = а.у - Ь.у;
return sqrt(dx*dx + dy*dy) ;
}
описывает функцию, которая вычисляет расстояние между двумя точками на плоскости. Это демонстрирует естественный способ использования структур для группировки данных в типовых приложениях.
Программа 1.3 содержит интерфейс, который воплощает описание типа данных для точек на плоскости: он использует структуру для представления точек и включает операцию вычисления расстояния между двумя точками. Программа 1.4 — это функция, которая реализует операцию. Подобная схема "интерфейс-реализация" используется для описания типов данных при любой возможности, поскольку в ней описание инкапсулировано (в интерфейсе), а реализация выражена в прямой и понятной форме. Тип данных используется в клиентской программе за счет включения интерфейса и компиляции реализации совместно с клиентом (либо с помощью функций раздельной компиляции). Программа реализации 1.4 включает интерфейс (программу 1.3) для обеспечения соответствия описания функции потребностям клиента.
Смысл в том, чтобы клиентские программы вполне могли обрабатывать точки без необходимости принимать какие-либо допущения об их представлении. Пример структуры point прост и включает два элемента одного типа. Обычно в структурах смешиваются различные типы данных.
Структуры позволяют группировать данные. Кроме того, в языке C++ можно связывать данные с операциями, которые должны с ними выполняться, путем использования механизма классов. С применением классов можно даже использовать программу, такую как 3.2, для обработки элементов типа point после описания соответствующих арифметических операций и преобразований типов для точек. Эта возможность использования ранее описанных операций высокого уровня абстракции даже для вновь созданных типов данных является одной из важных и выдающихся особенностей программирования на C++. Она основана на способности непосредственного описания собственных типов данных средствами языка. При этом не только связываются данные со структурой, но и точно задаются операции над данными (а также структуры данных и алгоритмы, которые их поддерживают) посредством классов. Классы формируют основу рассматриваемых в книге реализаций. Однако перед детальным обзором описания и использования классов (в главе 4) необходимо рассмотреть ряд низкоуровневых механизмов для управления данными и объединения их.
Помимо предоставления основных типов int, float и char, а также возможности встраивать их в составные типы с помощью оператора struct, C++ допускает косвенное управление данными. Указатель (pointer) — это ссылка на объект в памяти (обычно реализуется в виде машинного адреса). Чтобы объявить переменную а как указатель на целое значение, используется выражение int *a. Можно ссылаться на само целое значение с помощью записи *а. Допускается объявление указателей на любой тип данных. Унарный оператор & предоставляет машинный адрес объекта. Он удобен для инициализации указателей. Например, выражение *&а означает то же, что а.
Программа 1.4 Реализация структуры данных point
Здесь содержится описание функции distance, объявленной в программе 1.3.
Используется библиотечная функция вычисления квадратного корня.
#include <math.h>
#include "Point.h"
float distance(point a, point b)
{ float dx = a.x - b.x, dy = а.у - b.y;
return sqrt(dx*dx + dy*dy);
Косвенная ссылка на объект через указатель часто удобнее прямой ссылки, а также может оказаться более эффективной, особенно для больших объектов. Ещё важнее возможность использования указателей на структуру данных способами, которые поддерживают эффективные алгоритмы обработки данных. Указатели служат основой многих структур данных и алгоритмов.
Простой и важный пример использования указателей связан с описанием функции, которая должна возвращать множество значений. Например, следующая функция (использующая функции sqrt и atan2 из стандартной библиотеки) преобразует декартовы координаты в полярные:
polar(float x, float у, float *r, float *theta)
{ *r = sqrt(x*x + y*y); *theta = atan2(y, x); }
Аргументы передаются этой функции по значению — если функция присваивает новое значение переменной аргумента, эта операция является локальной и скрыта от вызывающей функции. Поэтому функция не может изменять указатели чисел с плавающей точкой г и theta, но способна изменять значения чисел с помощью косвенной ссылки. Например, если вызывающая функция содержит объявление
float a, b;
вызов функции
polar(1.0, 1.0, &а, &b)
приведет к тому, что для а установится значение 1.414214, а для b — значение 0.785398). Оператор & позволяет передавать адреса а и b в функцию, которая обрабатывает эти аргументы как указатели.
В языке C++ можно достичь того же результата посредством ссылочных параметров:
polar(float x, float у, floats r, floats theta)
{ г = sqrt(x*x + y*y); theta = atan2(y, x) ; }
Запись float& означает "ссылка на float". Ссылки можно рассматривать как встроенные указатели, которые автоматически сопровождаются при каждом использовании. Например, в этой функции ссылка на theta означает ссылку на любое значение float, используемое для второго аргумента вызывающей функции. Если вызывающая функция содержит объявление float a, b, как в примере из предыдущего абзаца, в результате вызова функции
Polar(1.0, 1.0, а, b)
переменной а будет присвоено значение 1.414214, а переменной b — значение 0.785398.