Производные Типы
Вот операции, создающие из основных типов новые типы:
* | указатель на |
*const | константный указатель на |
ссылка на | |
[] | вектор |
() | функция, возвращающая |
Например:
char* p | // указатель на символ |
char *const q | // константный указатель на символ |
char v[10] | // вектор из 10 символов |
Все вектора в качестве нижней границы индекса имеют ноль, поэтому в v десять элементов: v[0] ... v[9]. Функции объясняются в #1.5, ссылки в . Переменная указатель может содержать адрес объекта соответствующего типа:
char c; // ... p = c // p указывает на c
Унарное является операцией взятия адреса.
Другие типы модно выводить из основных типов (и типов, определенных пользователем) посредством операций описания:
* | указатель |
ссылка | |
[] | вектор |
() | функция |
и механизма определения структур. Например:
int* a; float v[10]; char* p[20]; // вектор из 20 указателей на символ void f(int); struct str { short length; char* p; };
Правила построения типов с помощью этих операций подробно объясняются в Основная идея состоит в том, что описание производного типа отражает его использование. Например:
int v[10]; // описывает вектор i = v[3]; // использует элемент вектора
int* p; // описывает указатель i = *p; // использует указываемый объект
Вся сложность понимания записи производных типов проистекает из того, что операции * и префиксные, а операции [] () постфиксные, поэтому для формулировки типов в тех случаях, когда приоритеты операций создают затруднения, надо использовать скобки. Например, поскольку приоритет у [] выше, чем у *, то
int* v[10]; // вектор указателей int (*p)[10]; // указатель на вектор
Большинство людей просто помнят, как выглядят наиболее обычные типы.
Описание каждого имени, вводимого в программе, может оказаться утомительным, особенно если их типы одинаковы. Но можно описывать в одном описании несколько имен. В этом случае описание содержит вместо одного имени список имен, разделенных запятыми. Например, два имени можно описать так:
int x, y; // int x; int y;
При описании производных типов можно указать, что операции применяются только к отдельным именам (а не ко всем остальным именам в этом описании). Например:
int* p, y; // int* p; int y; НЕ int* y; int x, *p; // int x; int* p; int v[10], *p; // int v[10]; int* p;
Мнение автора таково, что подобные конструкции делают программу менее удобочитаемой, и их следует избегать.
Кроме основных арифметических типов концептуально существует бесконечно много производных типов, сконструированных из основных типов следующим образом:
массивы объектов данного типа;
функции, получающие аргументы данного типа и возвращающие объекты данного типа;
указатели на объекты данного типа;
ссылки на объекты данного типа;
константы, являющиеся значениями данного типа;
классы, содержащие последовательность объектов различных типов, множество функций для работы с этими объектами и набор ограничений на доступ к этим объектам и функциям; структуры, являющиеся классами без ограничений доступа;
объединения, являющиеся структурами, которые могут в разное время содержать объекты разных типов.
В целом эти способы конструирования объектов могут применяться рекурсивно.
Объект типа void* (указатель на void) можно использовать для указания на объекты неизвестного типа.