C++ Типы данных
При программировании на языке программирования требуются различные переменные для хранения различных видов информации. Переменная сохраняет ячейку памяти значения, которое она хранит. Это означает, что при создании переменной в памяти резервируется некоторое пространство.
Вам может потребоваться хранить информацию различных типов данных (таких как символ, широкий символ, целое число, число с плавающей запятой, число с плавающей запятой двойной точности, логическое значение и т. д.). Операционная система выделит память в зависимости от типа данных переменной и определит, что хранить в зарезервированной памяти.
Базовые встроенные типы
C++ предоставляет программистам богатое разнообразие встроенных типов данных и пользовательских типов данных. В следующей таблице перечислены семь базовых типов данных C++:
| Type | Ключевые слова |
|---|---|
| Логический тип | bool |
| Символьный тип | char |
| целое число | int |
| Тип с плавающей запятой | float |
| Тип с плавающей запятой двойной точности | double |
| Void | void |
| Тип широкого символа | wchar_t |
Фактически wchar_t определяется так:
typedef short int wchar_t;
Следовательно, wchar_t фактически занимает столько же места, сколько short int.
Некоторые базовые типы можно модифицировать одним или несколькими модификаторами типа:
| Модификаторы | Описание | Пример |
|---|---|---|
signed | Обозначает знаковый тип (по умолчанию) | signed int x = -10; |
unsigned | Обозначает беззнаковый тип | unsigned int y = 10; |
short | Обозначает короткий целочисленный тип | short int z = 100; |
long | Обозначает длинный целочисленный тип | long int a = 100000; |
const | Указывает на константу, значение нельзя изменить | const int b = 5; |
volatile | Указывает, что переменная может быть неожиданно изменена, что запрещает оптимизацию компилятора. | volatile int c = 10; |
mutable | Указывает, что члены класса могут бытьconstизменены в объекте | mutable int counter; |
В следующей таблице показан объём памяти, необходимый для различных типов переменных при хранении значений в памяти, а также максимальные и минимальные значения, которые может хранить переменная этого типа.
Примечание:В разных системах могут быть различия; один байт — это 8 бит.
Примечание:По умолчанию int, short и long являются знаковыми.
Примечание:long int занимает 8 байт, а int всегда занимает 4 байта. Ранние компиляторы C определяли long int как занимающий 4 байта, а int — как занимающий 2 байта. Новые стандарты C/C++ совместимы с этой ранней настройкой.
| Типы данных | Описание | Размер (байты) | Пример диапазона/значения |
|---|---|---|---|
bool | Логический тип, представляющий true или false | 1 | trueилиfalse |
char | Символьный тип, обычно используется для хранения символов ASCII. | 1 | от -128 до 127 или от 0 до 255 |
signed char | Знаковый символьный тип | 1 | от -128 до 127 |
unsigned char | Беззнаковый символьный тип | 1 | от 0 до 255 |
wchar_t | Широкий символьный тип, используемый для хранения символов Unicode. | 2 или 4 | Зависит от платформы |
char16_t | 16-битный символьный тип Unicode (введён в C++11) | 2 | от 0 до 65,535 |
char32_t | 32-битный символьный тип Unicode (введён в C++11) | 4 | от 0 до 4,294,967,295 |
short | короткое целое число | 2 | от -32,768 до 32,767 |
unsigned short | Беззнаковое короткое целое | 2 | от 0 до 65,535 |
int | целое число | 4 | -2,147,483,648 до 2,147,483,647 |
unsigned int | Беззнаковый целочисленный тип | 4 | от 0 до 4,294,967,295 |
long | длинное целое | 4 или 8 | Зависит от платформы |
unsigned long | Беззнаковое длинное целое | 4 или 8 | Зависит от платформы |
long long | Целое типа long long (введено в C++11) | 8 | -9,223,372,036,854,775,808 до 9,223,372,036,854,775,807 |
unsigned long long | Беззнаковое целое типа long long (введено в C++11) | 8 | 0 до 18,446,744,073,709,551,615 |
float | Число с плавающей запятой одинарной точности | 4 | Приблизительно ±3.4e±38 (6-7 значащих цифр) |
double | Числа с плавающей запятой двойной точности | 8 | Примерно ±1.7e±308 (15 значащих цифр) |
long double | Числа с плавающей запятой расширенной точности | 8, 12 или 16 | Зависит от платформы |
Новые типы, добавленные в C++11
| Типы данных | Описание | Пример |
|---|---|---|
auto | Автоматическое выведение типа | auto x = 10; |
decltype | Получение типа выражения | decltype(x) y = 20; |
nullptr | Константа нулевого указателя | int* ptr = nullptr; |
std::initializer_list | Тип списка инициализации | std::initializer_list<int> list = {1, 2, 3}; |
std::tuple | Тип кортежа, который может хранить несколько значений разных типов. | std::tuple<int, float, char> t(1, 2.0, 'a'); |
Обратите внимание, что размер хранения различных типов связан с разрядностью системы, но в настоящее время основными являются в основном 64-битные системы.
Ниже перечислены различия в размере хранения между 32-битными и 64-битными системами (в Windows то же самое):
Из таблицы выше видно, что размер переменных будет варьироваться в зависимости от компилятора и используемого компьютера.
Следующий пример выведет размер различных типов данных на вашем компьютере.
Пример
В этом примере используетсяendl, это вставит символ новой строки после каждой строки,<<Операторы используются для передачи нескольких значений на экран,sizeof()Оператор используется для получения размера различных типов данных.
При компиляции и выполнении приведённого выше кода будут получены следующие результаты, которые могут отличаться в зависимости от используемого компьютера:
type: ************size************** bool: 所占字节数:1 最大值:1 最小值:0 char: 所占字节数:1 最大值: 最小值:? signed char: 所占字节数:1 最大值: 最小值:? unsigned char: 所占字节数:1 最大值:? 最小值: wchar_t: 所占字节数:4 最大值:2147483647 最小值:-2147483648 short: 所占字节数:2 最大值:32767 最小值:-32768 int: 所占字节数:4 最大值:2147483647 最小值:-2147483648 unsigned: 所占字节数:4 最大值:4294967295 最小值:0 long: 所占字节数:8 最大值:9223372036854775807 最小值:-9223372036854775808 unsigned long: 所占字节数:8 最大值:18446744073709551615 最小值:0 double: 所占字节数:8 最大值:1.79769e+308 最小值:2.22507e-308 long double: 所占字节数:16 最大值:1.18973e+4932 最小值:3.3621e-4932 float: 所占字节数:4 最大值:3.40282e+38 最小值:1.17549e-38 size_t: 所占字节数:8 最大值:18446744073709551615 最小值:0 string: 所占字节数:24 type: ************size**************
Производные типы данных
| Типы данных | Описание | Пример |
|---|---|---|
Array | Коллекция элементов одного типа | int arr[5] = {1, 2, 3, 4, 5}; |
Pointer | Тип, который хранит адрес памяти переменной | int* ptr = &x; |
Reference | Псевдоним переменной | int& ref = x; |
Function | Тип функции, представляющий сигнатуру функции | int func(int a, int b); |
Struct | Пользовательский тип данных, который может содержать несколько членов разных типов. | struct Point { int x; int y; }; |
Class | Пользовательский тип данных, поддерживающий инкапсуляцию, наследование и полиморфизм. | class MyClass { ... }; |
Union | Несколько членов совместно используют один и тот же блок памяти | union Data { int i; float f; }; |
Enum | Пользовательский набор целочисленных констант | enum Color { RED, GREEN, BLUE }; |
Псевдоним типа
| Псевдоним | Описание | Пример |
|---|---|---|
typedef | Определить псевдоним для существующего типа | typedef int MyInt; |
using | Определить псевдоним для существующего типа (введено в C++11) | using MyInt = int; |
Тип стандартной библиотеки
| Типы данных | Описание | Пример |
|---|---|---|
std::string | Строковый тип | std::string s = "Hello"; |
std::vector | Динамический массив | std::vector<int> v = {1, 2, 3}; |
std::array | Массив фиксированного размера (представлен в C++11) | std::array<int, 3> a = {1, 2, 3}; |
std::pair | Контейнер, хранящий два значения | std::pair<int, float> p(1, 2.0); |
std::map | Контейнер для пар «ключ-значение» | std::map<int, std::string> m; |
std::set | Набор уникальных значений | std::set<int> s = {1, 2, 3}; |
Объявление typedef
Можно использоватьtypedef, чтобы дать существующему типу новое имя. Ниже приведён синтаксис определения нового типа с помощью typedef:
typedef type newname;
Например, следующая инструкция сообщает компилятору, что feet — это другое имя для int:
typedef int feet;
Теперь следующее объявление полностью допустимо; оно создаёт целочисленную переменную distance:
feet distance;
Перечисляемый тип
Перечисляемый тип (перечисление) — это производный тип данных в C++, представляющий собой набор нескольких определяемых пользователем констант перечисления.
Если переменная может принимать лишь несколько возможных значений, её можно определить как перечисляемый тип. Так называемое «перечисление» означает перечисление значений переменной по одному, и значение переменной может находиться только в пределах перечисленных значений.
Чтобы создать enum, нужно использовать ключевое словоenum. Общий вид перечисляемого типа:
enum 枚举名{
标识符[=整型常数],
标识符[=整型常数],
...
标识符[=整型常数]
} 枚举变量;
Если перечисление не инициализировано, т. е. когда "= целочисленная константа" опущено, оно начинается с первого идентификатора.
Например, следующий код определяет перечисление color, а тип переменной c — color. В итоге c присваивается значение "blue".
enum color { red, green, blue } c;
c = blue;
По умолчанию значение первого имени равно 0, значение второго имени равно 1, значение третьего имени равно 2 и так далее. Однако можно также присвоить имени специальное значение, просто добавив начальное значение. Например, в следующем перечислении,greenЗначение равно 5.
enum color { red, green=5, blue };
Здесь,blueимеет значение 6, потому что по умолчанию каждое имя на 1 больше имени перед ним, но значение red всё ещё равно 0.
Преобразование типов
Преобразование типов — это преобразование значения одного типа данных в значение другого типа данных.
В C++ существует четыре вида преобразования типов: статическое преобразование, динамическое преобразование, преобразование const и reinterpret-преобразование.
Статическое приведение
Статическое преобразование — это принудительное преобразование значения одного типа данных в значение другого типа данных.
Статическое преобразование обычно используется для преобразований между объектами похожих типов, например для преобразования типа int в тип float.
Статическое приведение не выполняет никакой проверки типов во время выполнения, поэтому оно может привести к ошибкам времени выполнения.
Пример
Динамическое приведение
Динамическое преобразование (dynamic_cast) — это механизм в C++, используемый для понижающего приведения в иерархии наследования.
Динамическое преобразование обычно используется для преобразования указателя или ссылки на базовый класс в указатель или ссылку на производный класс.
Динамическое приведение выполняет проверку типов во время выполнения. Если преобразование не удаётся, оно возвращает nullptr для типов указателей и выбрасывает исключение std::bad_cast для типов ссылок.
Синтаксис:
dynamic_cast<目标类型>(表达式)
Целевой тип: Должен быть типом указателя или ссылки.
Выражение: Указатель или ссылка на базовый класс, которые необходимо преобразовать.
Пример: динамическое приведение типов указателей
Вывод:
Derived class method
Пример: динамическое приведение ссылочных типов
#include <typeinfo>
class Base {
public:
virtual ~Base() = default; // Базовый класс должен иметь виртуальные функции
};
class Derived : public Base {
public:
void show() {
std::cout << "Метод производного класса" << std::endl;
}
};
int main() {
Derived derived_obj;
Base& ref_base = derived_obj; // Ссылка базового класса, привязанная к объекту производного класса
try {
// Преобразовать ссылку базового класса в ссылку производного класса
Derived& ref_derived = dynamic_cast<Derived&>(ref_base);
ref_derived.show(); // Преобразование успешно, вызвать метод производного класса
} catch (const std::bad_cast& e) {
std::cout << Сбой динамического приведения: " << e.what() << std::endl;
}
return 0;
}
Вывод:
Derived class method
| Особенности | Тип указателя | Тип ссылки |
|---|---|---|
| Возвращаемое значение при неудачном преобразовании | returnnullptr | Генерация исключенияstd::bad_castИсключение |
| Применимые сценарии | Понижающее приведение, проверка типов во время выполнения | Понижающее приведение, проверка типов во время выполнения |
| Накладные расходы на производительность | Повышенный | Повышенный |
| Требование к базовому классу | Должен иметь виртуальные функции | Должен иметь виртуальные функции |
Приведение const
Преобразование const используется для преобразования объекта типа const в объект неконстантного типа.
Преобразование const можно использовать только для отбрасывания атрибута const; оно не может изменить тип объекта.
Пример
Переинтерпретирующее приведение
Переинтерпретирующее преобразование интерпретирует значение одного типа данных как значение другого типа данных, обычно используется для преобразований между разными типами данных.
Переинтерпретирующее преобразование не выполняет никакой проверки типов, что может привести к неопределённому поведению.
