Обзор

C++ — это статически типизированный, скомпилированный язык программирования общего назначения с учетом регистра и свободной формы, который поддерживает процедурное, объектно-ориентированное и обобщенное программирование.

C++ считается языком среднего уровня, поскольку он сочетает в себе функции языка высокого и низкого уровня.

Обучение C++ было разработано Бьерном Страуструпом, начиная с 1979 года в Bell Labs в Мюррей-Хилл, штат Нью-Джерси, в качестве усовершенствования языка C и первоначально называлось C с классами, но позже в 1983 году оно было переименовано в C++. .

C++ — это надмножество C, и практически любая легальная программа на C — это легальная программа на C++.

Переменные и типы

Полезность программ «Hello World», показанных в предыдущей главе, весьма сомнительна. Нам пришлось написать несколько строк кода, скомпилировать их, а затем выполнить получившуюся программу, лишь бы получить в результате простое предложение, написанное на экране. Конечно, было бы намного быстрее напечатать выходное предложение самостоятельно.

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

Давайте представим, что я прошу вас запомнить цифру 5, а затем я прошу вас одновременно запомнить и цифру 2. Вы только что сохранили в памяти два разных значения (5 и 2). Теперь, если я попрошу вас добавить 1 к первому названному мною числу, вы должны запомнить числа 6 (то есть 5+1) и 2 в своей памяти. Тогда мы могли бы, например, вычесть эти значения и получить в результате 4.

Весь процесс, описанный выше, аналогичен тому, что компьютер может делать с двумя переменными. Тот же процесс можно выразить на C++ с помощью следующего набора операторов:

1
2
3
4
a = 5;
b = 2;
a = a + 1;
result = a - b;

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

Теперь мы можем определить переменную как часть памяти для хранения значения.

Каждой переменной необходимо имя, которое идентифицирует ее и отличает от других. Например, в предыдущем коде именами переменных были a, b и result, но мы могли бы назвать переменные любыми именами, которые могли бы придумать, если бы они были действительными идентификаторами C++.

Идентификаторы

Допустимый идентификатор — это последовательность из одной или нескольких букв, цифр или символов подчеркивания (_). Пробелы, знаки препинания и символы не могут быть частью идентификатора. Кроме того, идентификаторы всегда должны начинаться с буквы. Они также могут начинаться с символа подчеркивания (_), но такие идентификаторы в большинстве случаев считаются зарезервированными для ключевых слов компилятора или внешних идентификаторов, а также идентификаторов, содержащих два последовательных символа подчеркивания в любом месте. Ни в коем случае они не могут начинаться с цифры.

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

alignas, alignof, and, and_eq, asm, auto, bitand, bitor, bool, break, case, catch, char, char16_t, char32_t, class, compl, const, constexpr, const_cast, continue, decltype, default, delete, do, двойное, динамическое_приведение, еще, перечисление, явное, экспорт, внешнее, ложное, плавающее, для, друга, переход, если, встроенное, целое, длинное, изменяемое, пространство имен, новое, без исключения, нет, не_экв, nullptr, оператор или, or_eq, private, protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_assert, static_cast, struct, switch, template, this, thread_local, throw, true, try, typedef, typeid, typename, union, беззнаковый, с использованием, виртуальный, недействительный, изменчивый, wchar_t, в то время как, xor, xor_eq

Конкретные компиляторы также могут иметь дополнительные специальные зарезервированные ключевые слова.

Очень важно. Язык C++ чувствителен к регистру. Это означает, что идентификатор, написанный заглавными буквами, не эквивалентен другому идентификатору с тем же именем, но написанному строчными буквами. Таким образом, например, переменная RESULT отличается от переменной результата или переменной результата. Это три разных идентификатора, идентифицирующих три разные переменные.

Основные типы данных

Значения переменных хранятся где-то в неуказанном месте в памяти компьютера как нули и единицы. Нашей программе не нужно знать точное место хранения переменной; он может просто ссылаться на него по имени. Программа должна знать, какие данные хранятся в переменной. Хранение простого целого числа отличается от хранения буквы или большого числа с плавающей запятой; даже несмотря на то, что все они представлены нулями и единицами, они интерпретируются по-разному и во многих случаях занимают разный объем памяти.

Фундаментальные типы данных — это базовые типы, реализованные непосредственно языком и представляющие базовые единицы хранения, изначально поддерживаемые большинством систем. В основном их можно разделить на:

  • Типы символов. Они могут представлять один символ, например «A» или «$». Самый простой тип — это char, представляющий собой однобайтовый символ. Другие типы также предусмотрены для более широких символов.
  • Числовые целые типы. Они могут хранить целое числовое значение, например 7 или 1024. Они бывают разных размеров и могут быть как со знаком, так и без знака. , в зависимости от того, поддерживают ли они отрицательные значения или нет.
  • Типы с плавающей запятой. Они могут представлять действительные значения, например 3,14 или 0,01, с разным уровнем точности, в зависимости от того, какой из трех типов с плавающей запятой используется.
  • Булев тип. Логический тип, известный в C++ как bool, может представлять только одно из двух состояний: истинное или ложное.

Вот полный список основных типов в C++:
Имена групповых типов*Примечания по размеру/точностиТипы символовcharРазмер ровно один байт. Не менее 8 бит.char16_t Не меньше, чем char. Не менее 16 бит.char32_t Не меньше char16_t. Не менее 32 бит.wchar_tМожет представлять самый большой поддерживаемый набор символов. Целочисленные типы (со знаком)signed charТого же размера, что и char. Не менее 8 бит. signed short int Не меньше char. Не менее 16 бит. signed int Не меньше короткого. Не менее 16 бит. signed long intНе меньше, чем int. Не менее 32 бит. signed long long int Не меньше, чем long. Не менее 64 бит. Целочисленные типы (без знака)unsigned char (того же размера, что и их аналоги со знаком) unsigned short intunsigned intunsigned long intunsigned long long intТипы с плавающей запятойfloatdoubleТочность не ниже floatlong doubleТочность не ниже doubleBoolean typeboolVoid typevoidno storageNull pointerdecltype(nullptr)
* Имена некоторых целочисленных типов могут быть сокращены без их компонентов со знаком и целым числом — для идентификации типа требуется только часть, выделенная не курсивом, часть, выделенная курсивом, необязательна. То есть signed short int может быть сокращено как signed short, short int или просто short; все они идентифицируют один и тот же фундаментальный тип.

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

Обратите внимание на панель выше, что кроме char (который имеет размер ровно один байт), ни один из основных типов не имеет указанного стандартного размера (но не более минимального размера). Поэтому для типа не требуется (а во многих случаях и нет) именно этого минимального размера. Это не означает, что эти типы имеют неопределенный размер, но что не существует стандартного размера для всех компиляторов и машин; каждая реализация компилятора может указывать размеры для этих типов, которые наилучшим образом соответствуют архитектуре, в которой будет выполняться программа. Эта довольно общая спецификация размера для типов дает языку C++ большую гибкость, позволяющую адаптировать его для оптимальной работы на всех типах платформ, как настоящих, так и будущих.

Приведенные выше размеры шрифтов выражены в битах; чем больше битов у типа, тем больше разных значений он может представлять, но в то же время он занимает больше места в памяти:

SizeUnique представляемые значенияNotes8-bit256= 2816-bit65 536= 21632-bit4 294 967 296= 232 (~4 миллиарда)64-bit18 446 744 073 709 551 616= 264 (~18 миллиардов миллиардов)
Для целочисленных типов, имеющих более представляемые значения означают, что диапазон значений, которые они могут представлять, больше; например, 16-разрядное целое число без знака может представлять 65 536 различных значений в диапазоне от 0 до 65 535, в то время как его аналог со знаком в большинстве случаев может представлять значения от -32 768 до 32 767. Обратите внимание, что диапазон положительные значения в знаковых типах примерно вдвое меньше, чем в беззнаковых, из-за того, что один из 16 бит используется для знака; это относительно небольшая разница в диапазоне, и она редко оправдывает использование беззнаковых типов, основываясь только на диапазоне положительных значений, которые они могут представлять.

Для типов с плавающей запятой размер влияет на их точность, так как имеет больше или меньше битов для их значимости и степени.

Если размер или точность типа не имеет значения, то обычно выбираются char, int и double для представления символов, целых чисел и значений с плавающей запятой соответственно. Другие типы в соответствующих группах используются только в особых случаях.

Свойства фундаментальных типов в конкретной системе и реализации компилятора можно получить, используя классы numeric_limits (см. стандартный заголовок ‹limits›). Если по какой-то причине требуются типы определенных размеров, библиотека определяет определенные псевдонимы типов фиксированного размера в заголовке ‹cstdint›.

Типы, описанные выше (символы, целые числа, числа с плавающей запятой и логические значения), вместе известны как арифметические типы. Но существуют два дополнительных фундаментальных типа: void, определяющий отсутствие типа; и тип nullptr, который является специальным типом указателя. Оба типа будут обсуждаться далее в следующей главе об указателях.

C++ поддерживает широкий спектр типов, основанных на рассмотренных выше фундаментальных типах; эти другие типы известны как составные типы данных и являются одной из основных сильных сторон языка C++. Мы также рассмотрим их более подробно в следующих главах.

Объявление переменных

C++ является строго типизированным языком и требует, чтобы каждая переменная была объявлена ​​с указанием ее типа перед ее первым использованием. Это информирует компилятор о размере памяти, которую нужно зарезервировать для переменной, и о том, как интерпретировать ее значение. Синтаксис для объявления новой переменной в C++ Training прост: мы просто пишем тип, за которым следует имя переменной (т. е. ее идентификатор). Например:

1
2
int a;
float mynumber;

Это два допустимых объявления переменных. Первый объявляет переменную типа int с идентификатором a. Второй объявляет переменную типа float с идентификатором mynumber. После объявления переменные a и mynumber могут использоваться в остальной части их области действия в программе.
Если объявляется более одной переменной одного и того же типа, их все можно объявить в одном операторе, разделив их идентификаторы символом запятые. Например:

int a, b, c;

Здесь объявляются три переменные (a, b и c), все они имеют тип int и имеют точно такое же значение, как:

1
2
3
int a;
int b;
int c;

Чтобы увидеть, как объявления переменных выглядят в действии в программе, давайте взглянем на весь код C++ примера с вашей мысленной памятью, предложенного в начале этой главы:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// operating with variables
#include <iostream>
using namespace std;
int main ()
{
  // declaring variables:
  int a, b;
  int result;
  // process:
  a = 5;
  b = 2;
  a = a + 1;
  result = a - b;
  // print out the result:
  cout << result;
  // terminate the program:
  return 0;
}
4

Редактировать и запустить

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

Инициализация переменных

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

В C++ существует три способа инициализации переменных. Все они эквивалентны и напоминают эволюцию языка на протяжении многих лет:

Первый, известный как c-подобная инициализация (поскольку он унаследован от языка C), состоит из добавления знака равенства, за которым следует значение, которым инициализируется переменная:

идентификатор типа = начальное_значение;
Например, чтобы объявить переменную типа int с именем x и инициализировать ее нулевым значением с того же момента, когда она была объявлена, мы можем написать:

int x = 0;

Второй метод, известный как инициализация конструктора (представленный в языке C++), заключает начальное значение в круглые скобки (()):

идентификатор типа (initial_value);
Например:

int x (0);

Наконец, третий метод, известный как uniform initialization, аналогичен предыдущему, но с использованием фигурных скобок ({}) вместо скобок (он был введен в редакции стандарта C++ в 2011 г.):

идентификатор типа {initial_value};
Например:

int x {0};

Все три способа инициализации переменных допустимы и эквивалентны в C++.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// initialization of variables
#include <iostream>
using namespace std;
int main ()
{
  int a=5;               // initial value: 5
  int b(3);              // initial value: 3
  int c{2};              // initial value: 2
  int result;            // initial value undetermined
  a = a + b;
  result = a - c;
  cout << result;
  return 0;
}
6

Редактировать и запустить

Вывод типа: auto и decltype

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

1
2
int foo = 0;
auto bar = foo;  // the same as: int bar = foo;

Здесь bar объявлен как имеющий автоматический тип; следовательно, тип bar — это тип значения, используемого для его инициализации: в данном случае используется тип foo, то есть int.

Неинициализированные переменные также могут использовать вывод типа со спецификатором decltype:

1
2
int foo = 0;
decltype(foo) bar;  // the same as: int bar;

Здесь bar объявлен как имеющий тот же тип, что и foo.

auto и decltype — мощные функции, недавно добавленные в язык. Но введенные ими функции вывода типов предназначены для использования либо тогда, когда тип нельзя получить другими способами, либо когда его использование улучшает читаемость кода. Два приведенных выше примера, вероятно, не относятся ни к одному из этих вариантов использования. На самом деле они, вероятно, ухудшили читаемость, так как при чтении кода нужно искать тип foo, чтобы действительно узнать тип bar.

Знакомство со строками

Фундаментальные типы представляют собой самые основные типы, обрабатываемые машинами, на которых может выполняться код. Но одной из главных сильных сторон языка C++ является его богатый набор составных типов, из которых основные типы являются простыми строительными блоками.

Примером составного типа является класс string. Переменные этого типа могут хранить последовательности символов, такие как слова или предложения. Очень полезная функция!

Первое отличие фундаментальных типов данных состоит в том, что для объявления и использования объектов (переменных) этого типа программа должна включать заголовок, в котором тип определен в стандартной библиотеке (заголовок ‹string›):

1
2
3
4
5
6
7
8
9
10
11
12
// my first string
#include <iostream>
#include <string>
using namespace std;
int main ()
{
  string mystring;
  mystring = "This is a string";
  cout << mystring;
  return 0;
}
This is a string

Редактировать и запустить

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

1
2
3
string mystring = "This is a string";
string mystring ("This is a string");
string mystring {"This is a string"};

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// my first string
#include <iostream>
#include <string>
using namespace std;
int main ()
{
  string mystring;
  mystring = "This is the initial string content";
  cout << mystring << endl;
  mystring = "This is a different string content";
  cout << mystring << endl;
  return 0;
}
This is the initial string content
This is a different string content

Редактировать и запустить

Примечание. Вставка манипулятора endl end в строку (печатает символ новой строки и очищает поток).

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

Дополнительные сведения о стандартных строках C++ см. в справочнике по классам строк.