X Tutup
The Wayback Machine - https://web.archive.org/web/20220815235800/https://ru.cppreference.com/w/cpp/language/type
Пространства имён
Варианты
Действия

Тип

Материал из cppreference.com
< cpp‎ | language
 
 
 
 

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


Содержание

[править] Классификация типов

Система типов C++ состоит из следующих типов:

  • тип void (смотрите также std::is_void);
  • тип std::nullptr_t (начиная с C++11) (смотрите также std::is_null_pointer);
  • арифметические типы (смотрите также std::is_arithmetic):
  • тип bool;
  • символьные типы:
  • короткие символьные типы:
  • обычные символьные типы (char, signed char, unsigned char)
  • тип char8_t (начиная с C++20)
  • широкие символьные типы (char16_t (начиная с C++11), char32_t (начиная с C++11), wchar_t);
  • знаковые целые типы (short int, int, long int, long long int);
  • беззнаковые целые типы (unsigned short int, unsigned int, unsigned long int, unsigned long long int);
  • lvalue-ссылка на объектные типы;
  • lvalue-ссылка на функциональные типы;
  • rvalue-ссылка на объектные типы;
  • rvalue-ссылка на функциональные типы;

Для каждого типа, кроме ссылки и функции, система типов поддерживает три дополнительные версии cv-квалификатора этого типа, (const, volatile и const volatile).

Типы сгруппированы в различные категории в зависимости от их свойств:

  • объектные типы, это (возможно, cv-квалифицированные) типы, которые не являются функциональными типами, ссылочными типами, или, возможно, cv-квалифицированным типом void (смотрите также std::is_object);
  • скалярные типы, это (возможно, cv-квалифицированные) объектные типы, не являющиеся типами массивов или классов (смотрите также std::is_scalar);
  • тривиальные типы (смотрите также std::is_trivial), POD типы (смотрите также std::is_pod), литеральные типы (смотрите также std::is_literal_type), и другие категории, перечисленные в библиотеке классов-свойств типов или в требованиях к именованию типов.

[править] Именование типов

Имя можно объявить, сославшись на тип с помощью:

В программах на C++ часто приходится ссылаться на типы, не имеющие имён; синтаксис для этого известен как идентификатор типа. Синтаксис идентификатора типа, который именует тип T, в точности совпадает с синтаксисом объявления переменной или функции типа T с опущенным идентификатором, за исключением того, что последовательность-спецификаторов-объявления грамматики объявления ограничена последовательностью-спецификаторов-типа, и эти новые типы могут быть определены только в том случае, если идентификатор типа появляется в правой части объявления псевдонима нешаблонного типа.

int * p;              // объявление указателя на int
static_cast<int*>(р); // идентификатор типа, это "int*"
 
int a[3];   // объявление массива из 3-х int
new int[3]; // идентификатор типа, это "int[3]" (называемый new идентификатор типа)
 
int (*(*x[2])())[3]; // объявление массива из 2-х указателей на функцию
                     // возвращающую указатель на массив из 3-х int
new (int (*(*[2])())[3]); // идентификатор типа, это "int (*(*[2])())[3]"
 
void f(int);                    // объявление функции, принимающей int и возвращающей void
std::function<void(int)> x = f; // тип параметра шаблона, это идентификатор типа
                                // "void(int)"
std::function<auto(int) -> void> y = f; // то же самое
 
std::vector<int> v;       // объявление вектора значений int
sizeof(std::vector<int>); // идентификатор типа, это "std::vector<int>"
 
struct { int x; } b;         // создаёт новый тип и объявляет объект b этого типа
sizeof(struct{ int x; });    // ошибка: нельзя определять новые типы в выражении sizeof
using t = struct { int x; }; // создаёт новый тип и объявляет t, как псевдоним этого типа
 
sizeof(static int); // ошибка: спецификаторы класса памяти не являются частью
                    // последовательности-спецификаторов-типа
std::function<inline void(int)> f; // ошибка: недопустимы спецификаторы функций

Часть декларатора грамматики объявления с удалённым именем называется абстрактным декларатором.

Идентификатор типа может использоваться в следующих ситуациях:

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

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

[править] Конкретизированный спецификатор типа

Конкретизированные спецификаторы типа могут использоваться для ссылки на ранее объявленное имя (класса, структуры или объединения) или на ранее объявленное имя перечисления, даже если имя было скрыто объявлением не типа. Их также можно использовать для объявления новых имён классов.

Подробнее смотрите конкретизированный спецификатор типа.

[править] Статический тип

Тип выражения, полученного в результате анализа программы во время компиляции, известный как статический тип выражения. Статический тип не изменяется во время выполнения программы.

[править] Динамический тип

Если некоторое выражение glvalue ссылается на полиморфный объект, тип его последнего производного объекта известен как динамический тип.

// дано
struct B {virtual ~B() {} }; // полиморфный тип
struct D: B {}; // полиморфный тип
D d; // последний производный объект
B* ptr = &d;
// статический тип (*ptr) это B
// динамический тип (*ptr) это D

Для выражений prvalue динамический тип всегда такой же, как и статический.

[править] Неполный тип

Следующие типы являются неполными типами:

Все остальные типы полные.


Любой из следующих контекстов требует, чтобы тип T был полным:

(В общем, когда размер и выравнивание T должны быть известны.)

Если какая-либо из этих ситуаций возникает в единице трансляции, определение типа должно появиться в той же единице трансляции. В противном случае это не требуется.

Неполностью определенный тип объекта можно завершить:

  • Тип класса (например, class X) может быть неполным в какой-то точке в единице трансляции и завершён позже; тип class X один и тот же тип в обеих точках:
struct X;             // X неполный тип
extern X* xp;         // xp указатель на неполный тип
 
void foo() {
  xp++;               // некорректно сформировано: X неполный
}
 
struct X { int i; };  // теперь X полный тип
 
X x;
void bar() {
  xp = &x;            // OK: тип является “указателем на X”
  xp++;               // OK: X полный
}
  • Объявленный тип объекта массива может быть массивом неполного типа класса и, следовательно, неполным; если тип класса завершается позже в единице трансляции, тип массива становится полным; тип массива в этих двух точках имеет тот же тип.
  • Объявленный тип объекта массива может быть массивом с неизвестными границами и, следовательно, быть неполным в какой-то точке в единице трансляции и завершиться позже; типы массивов в этих двух точках ("массив типа T с неизвестными границами" и "массив N элементов типа T") относятся к разным типам.

Тип указателя на массив с неизвестной границей или на тип, определённый объявлением typedef, как массив с неизвестной границей, не могут быть завершены.

extern int arr[];   // тип arr неполный
typedef int UNKA[]; // UNKA неполный тип
UNKA* arrp;         // arrp указатель на неполный тип
UNKA** arrpp;
 
void foo() {
  arrp++;           // ошибка: неполный тип
  arrpp++;          // OK: sizeof UNKA* известно
}
 
int arr[10];        // теперь тип arr завершён
 
void bar() {
  arrp = &arr;      // ошибка: различные типы
  arrp++;           // ошибка: UNKA не может быть завершён
}

[править] Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 328 C++98 элементы класса неполного типа не запрещены, если объект
типа класса никогда не создаётся
нестатические элементы данных
класса должны быть полными
CWG 977 C++98 момент, когда тип перечисления становится полным в своём
определении, был неясен
тип полон после определения базового типа
CWG 1362 C++98 определяемые пользователем преобразования в тип T* или T&,
требуют чтобы T был завершённым
не требуется
CWG 2006 C++98 cv-квалифицированные типы void были объектным типом и
полным типом
исключены из обеих категорий
CWG 2448 C++98 только cv-квалифицированные типы могут быть
целочисленными типами и типами с плавающей запятой
разрешены cv-квалифицированные типы

[править] Смотрите также

X Tutup