Язык программирования C++. Пятое издание - Стенли Липпман
Шрифт:
Интервал:
Закладка:
// string — библиотечный тип, представляющий последовательность
// символов переменной длины
std::string book("0-201-78345-X"); // book инициализирована строковым
// литералом
В определении переменной book использован библиотечный тип std::string. Подобно классу iostream (см. раздел 1.2), класс string определен в пространстве имен std. Более подробная информация о классе string приведена в главе 3, а пока достаточно знать то, что тип string представляет последовательность символов переменной длины. Библиотечный тип string предоставляет несколько способов инициализации строковых объектов. Один из них — копирование строкового литерала (см. раздел 2.1.3). Таким образом, переменная book инициализируется символами 0-201-78345-X.
Терминология. Что такое объект?Программисты языка С++ используют термин объект (object) часто, и не всегда по делу. В самом общем определении объект — это область памяти, способная содержать данный и обладающая типом.
Одни программисты используют термин объект лишь для переменных и экземпляров классов. Другие используют его, чтобы различать именованные и неименованные объекты, причем для именованных объектов используют термин переменная (variable). Третьи различают объекты и значения, используя термин объект для тех данных, которые могут быть изменены программой, и термин значение (value) — для тех данных, которые предназначены только для чтения.
В этой книге используется наиболее общий смысл термина объект, т.е. область памяти, для которой указан тип. Здесь под объектом подразумеваются практически все используемые в программе данные, независимо от того, имеют ли они встроенный тип или тип класса, являются ли они именованными или нет, предназначены только для чтения или допускают изменение.
ИнициализаторыИнициализация (initialization) присваивает объекту определенное значение в момент его создания. Используемые для инициализации переменных значения могут быть насколько угодно сложными выражениями. Когда определяется несколько переменных, имена всех объектов следуют непосредственно друг за другом. Таким образом, вполне возможно инициализировать переменную значением одной из переменных, определенных ранее в том же определении.
// ok: переменная price определяется и инициализируется прежде,
// чем она будет использована для инициализации переменной discount
double price = 109.99, discount = price * 0.16;
// ok: Вызов функции applyDiscount() и использование ее возвращаемого
// значения для инициализации переменной salePrice
salePrice = applyDiscount(price, discount);
Инициализация в С++ — на удивление сложная тема, и мы еще не раз вернемся к ней. Многих программистов вводит в заблуждение использование символа = при инициализации переменной. Они полагают, что инициализация — это такая форма присвоения, но в С++ инициализация и присвоение — совершенно разные операции. Эта концепция особенно важна, поскольку во многих языках это различие несущественно и может быть проигнорировано. Тем не менее даже в языке С++ это различие зачастую не имеет значения. Однако данная концепция крайне важна, и мы будем повторять это еще не раз.
Инициализация — это не присвоение. Инициализация переменной происходит при ее создании. Присвоение удаляет текущее значение объекта и заменяет его новым.
Списочная инициализацияТема инициализации настолько сложна потому, что язык поддерживает ее в нескольких разных формах. Например, для определения переменной units_sold типа int и ее инициализации значением 0 можно использовать любой из следующих четырех способов:
int units_sold = 0;
int units_sold = {0};
int units_sold{0};
int units_sold(0);
Использование фигурных скобок для инициализации было введено новым стандартом. Ранее эта форма инициализации допускалась лишь в некоторых случаях. По причинам, описанным в разделе 3.3.1, эта форма инициализации известна как списочная инициализация (list initialization). Списки инициализаторов в скобках можно теперь использовать всегда, когда инициализируется объект, и в некоторых случаях, когда объекту присваивается новое значение.
При использовании с переменными встроенного типа эта форма инициализации обладает важным преимуществом: компилятор не позволит инициализировать переменные встроенного типа, если инициализатор может привести к потере информации:
long double ld = 3.1415926536;
int a{ld}, b = {ld}; // ошибка: преобразование с потерей
int с(ld), d = ld; // ok: но значение будет усечено
Компилятор откажет в инициализации переменных а и b, поскольку использование значения типа long double для инициализации переменной типа int может привести к потере данных. Как минимум, дробная часть значения переменной ld будет усечена. Кроме того, целочисленная часть значения переменной ld может быть слишком большой, чтобы поместиться в переменную типа int.
То, что здесь представлено, может показаться тривиальным, в конце концов, вряд ли кто инициализирует переменную типа int значением типа long double непосредственно. Однако, как представлено в главе 16, такая инициализация может произойти непреднамеренно. Более подробная информация об этих формах инициализации приведена в разделах 3.2.1 и 3.3.1.
Инициализация по умолчаниюПри определении переменной без инициализатора происходит ее инициализация по умолчанию (default initialization). Таким переменным присваивается значение по умолчанию (default value). Это значение зависит от типа переменной и может также зависеть от того, где определяется переменная.
Значение объекта встроенного типа, не инициализированного явно, зависит от того, где именно он определяется. Переменные, определенные вне тела функции, инициализируются значением 0. За одним рассматриваемым вскоре исключением, определенные в функции переменные встроенного типа остаются неинициализированными (uninitialized). Значение неинициализированной переменной встроенного типа неопределенно (см. раздел 2.1.2). Попытка копирования или получения доступа к значению неинициализированной переменной является ошибкой.
Инициализацию объекта типа класса контролирует сам класс. В частности, класс позволяет определить, могут ли быть созданы его объекты без инициализатора. Если это возможно, класс определяет значение, которое будет иметь его объект в таком случае.
Большинство классов позволяет определять объекты без явных инициализаторов. Такие классы самостоятельно предоставляют соответствующее значение по умолчанию. Например, новый объект библиотечного класса string без инициализатора является пустой строкой.
std::string empty; // неявно инициализируется пустой строкой
Sales_item item; // объект Sales_item инициализируется
// значением по умолчанию
Однако некоторые классы требуют, чтобы каждый объект был инициализирован явно. При попытке создать объект такого класса без инициализатора компилятор пожалуется на это.
Значение неинициализированных объектов встроенного типа, определенных в теле функции, неопределенно. Значение не инициализируемых явно объектов типа класса определяется классом.
Упражнения раздела 2.2.1Упражнение 2.9. Объясните следующие определения. Если среди них есть некорректные, объясните, что не так и как это исправить.
(а) std::cin >> int input_value; (b) int i = { 3.14 };
(с) double salary = wage = 9999.99; (d) int i = 3.14;
Упражнение 2.10. Каковы исходные значения, если таковые вообще имеются, каждой из следующих переменных?
std::string global str;
int global_int;
int main() {
int local_int;
std::string local_str;
}
2.2.2. Объявления и определения переменных
Для обеспечения возможности разделить программу на несколько логических частей язык С++ предоставляет технологию, известную как раздельная компиляция (separate compilation). Раздельная компиляция позволяет составлять программу из нескольких файлов, каждый из которых может быть откомпилирован независимо.
При разделении программы на несколько файлов необходим способ совместного использования кода этих файлов. Например, код, определенный в одном файле, возможно, должен использовать переменную, определенную в другом файле. В качестве конкретного примера рассмотрим объекты std::cout и std::cin. Классы этих объектов определены где-то в стандартной библиотеке, но все же наши программы могут использовать их.