Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 208
Текст из файла (страница 208)
911 В.б. Неявное преобразование типов В.6.2.2. Преобразования чисел с плавающей точкой Число с плавающей точкой может преобразовываться в число с плавающей точкой другого типа. Гели исходное значение можно точно представить в конечном типе, результат будет изначальным численным значением. Если исходное значение лежит между двумя соседними значениями в конечном типе, результат будет одним из этих значений. В противном случае результат не опреде.лен.
Например: /1оаг/= И.Т МАХ; //нпибвльшее значение с плавиюизвй точкой с1аиЫв д =Я // ~равильнв; д==/ /2оа1/2 = сй // правильно:/2 ==/ йвиЫе йх = 1ЗВЬ МАХ; //наибольисве значение йпийв 11ааГ)в' — сИ; //нв определено, если сйр МАХкОВЬ МАХ В.6.2.3. Преобразования указателей и ссылок Любой указатель на объектный тип может быть неявно преобразован в посс(' (9 5.6). Указатель (ссылку) на производный класс можно неявно преобразовать в указатель (ссылку) на доступный и недвусмысленно определяемый базовый класс (6 12.2). Отметим, что указатель на функцию или указатель на член не может быть неявно преобразован в ооссс".
Константное выражение Я В.5), которое при своем вычислении равно О, можно неявно преобразовать в любой указательный тип или тип указателя па член (6 5.1. 1). Например: 1пГ*р = 1 1 ! ! ! ! ННН 1НН 1НЦ. Т' может неявно преобразоваться в сопИ Т' (9 5А.1). Аналогично, Тй может неявно преобразоваться в солв1 Т8. В.6.2.4. Преобразования указателей на члены Указатели и ссылки на члены могут неявно преобразовываться, как описано в 9 15.5.1. В.6.2.5. Преобразования в логические переменные Указатели, интегральные значения н числа с плавающей точкой могут неявно преобразовываться в логический тип Ьоо1 (9 4.2). Ненулевое значение преобразуется в 1 ив, а нулевое — в /а1ве. Например: аасс2/йп~' р, сп1 с1 //йив, если р!=0 //Ьав, всли0=0 Ьоа!1з паг гвга=р; Ьаа1 Ь2 =й В.6.2.6. Преобразования чисел с плавающей точкой в целые и обратно Когда число с плавающей точкой преобразуется в целое, его дробная часть отбрасыва- ется.
Иными словами, преобразование из числа с плавающей точкой в целое, урезает число. Например, значение 1л1 11.6) равно 1. Гели урезанное значение не может быть представлено конечным типом, поведение не определено. Например: 912 Приложение В. Технические подробности //! становится ровные 2 // поведение не определено для 8-битных сйаа //2000 не представить 8 Виталю !а!1=2.7; сйагЬ =20007 Преобразование из целого типа в тип с плавающей точкой настолько математически корректно, насколько позволяет аппаратура. Потеря точности происходит, если целочисленное значение нельзя точно представить типом с плавающей точкой. Например, 1н11 =/(оаг(123456 7890) с1аевсйесй /а1!ед(); сйагсйесйед (1а11); ( сйагс = 1; //опасно: не переносшю 7ф В.б.2.1) (7 (1 ы с) 1йгош сйесй ~а!!ес((); ге!ига с; ооайту сос(е (1п11) ( сйаг с = сйесйед (1); 0- ) Чтобы урезать число с гарантией переносимости, нужно воспользоваться питег(с 11т11в (9 22.2).
В.6.3. Обычные арифметические преобразования Эти преобразования выполняются над операндами бинарного оператора, чтобы привести их к общему типу, который потом используется как тип результата: ) Ц Если один из операндов относится к типу !олпа!оиЫе, другой тоже преобразуется в !опд с!оиЫе. В противном случае, если один из операндов относится к типу с(оиЫе, другой тоже преобразустся в ИоиЫе. В противном случае, если один из операндов относится к типу77оа1, другой тоже преобразуется в /!оа1. ° В противном случае над обоими операндами производится интегральное продвижение Гз В.6,1).
) 2] Затем, если один из операндов относится к типу ипв(днес(1опд, другой тоже преобразуется в ипв/ппес1 1оап. В противном случае, если один из операндов относится к типу !олд Ьа1, а другой к типу илв(унес( 1п1, то если 1оаа'1л! может представить все значения типа оставит!со значением 12о456 703б, сели в машине и 1л1, и71оа! представляются 32 битами. Ясно, что потенциально разрушающих значение неявных преобразований лучше избсгать. Фактичсски, компилятор может выявить некоторые очевидно опасные преобразования и предупредить о них — например, о преобразовании числа с плавающей точкой в целое или 1опд(п! в сйаг.
Однако полное выявление во время компиляции нереалистично, поэтому программист должен быть осторожен. Когда просто «быть осторожным» недостаточно, он долекен вставлять явные проверки. Например: 913 В.7. Многомерные массивы ипзщпесУ Уп1, ипзудпесУ(п1 преобразуется в уопя !ну иначе оба операнда преобразуются в ипз(япесУ !опт уп1. В противном случае, если один из операндов относится к типу !оса, другой тоже преобразуется в !опд.
В противном случае, если один из операндов относится к типу ипз(днес!, другой тоже преобразуется в ипз!днес!. В противном случае оба операнда спу. В.7. Многомерные массивы Не так уж репко нам бывает нужен вектор векторов, вектор векторов из векторов и т. д, Вопрос в том, как представляются такие многомерные вектора в С++.
Здесь я сначала покажу, как пользоваться стандартным библиотечным классам аес1ог. Потом я познакомлю вас с многомерными массивами, как они выглядят в программах на С и С++ при использовании только встроенных средств. В.7.1. Вектора Стандартный оес1ог (9 16.3) предоставляет вполне общее решение: эес1ог~ сес1ог <ту» т(З, эесуог .уп1> (5)), Так создастся вектор из трех векторов с пятью целыми элементами, в котором каждый из 15 целых элементов по умолчанию равен О, Мы можем присвоить новые значения целым элементам следующим образам: ио10(ии'1 и () уог (упг у = О; 2<т.стае (); 10-0) ( уог (!псу=э уст(2)сузе ()у++) т(у)(у) = 10 2+у; ) или графически: 202; '2 ссэ' г0070110| (00 00] 212: '2 0Я вЂ” = (2т012г12 (1 2710) 222: ~$~ —— ~20 21 22 23 21 Каждая реализация шаблона эес1ог содержит указатель на сго элементы плюс число элементов.
Как правило, элементы содержатся в массиве. Для иллюстрации я задал каждому Уп1 начальное значение, представляющее его координаты. Доступ к элементам осуществляется путем двайнога индексирования. 11апример, т(У٠— это усй элемент с-го вектора. Мы можем распечатать т следующим образом: во20(рг2п1 т () Приложение В. Технические подробности 914 )ог (т 1 1 = 0; 1<т.втее (); 1++) ( 1ог (1п1 1'= 0 1<т[1)еие () 1++) соиг «т[1)[1) « '11'; сои1« '1п'; ) ) Получится: О 1 2 З 10 П 12 1З 20 21 22 2З 14 24 Отметим, что т является вектором из векторов, в отличие от простого многомерного массива. Поэтому, в частности, возможно провести изменение размера Я 18.3,8) элементов. Например: воЫгее1саре т()п1 ие) 1Ог ()п1 с = 0; 1<т елее (); 1<<) т [1) гевтее (пв); Нет необходимости, чтобы вектора еес1ог<1п1> в еес1ог< вес1ог <1п1» имели одинако- вый размер. В.7.2 Массивы Встроенные массивы являются главным источником ошибок — особенно когла они используются для построения многомерных массивов.
Для новичков они также являются главным источником смущения и непонимания. По возможности пользуйтесь шаблонами еес1ог, еа1аггау, в1г)пд и т. п. Многомерные массивы представляются как массивы массивов. Массив Зх5 объявляется следуюгцим образом; !п1та[З)[5); О Змассива по 5 целых в каждом Для массивов размерность лолжна задаваться как часть определения.
Мы можем инициализировать та следуюшим образом: еон1т11 та() 1ог (1п11 = 0; 1<3; 1<-<-) ( Хог (1п11'= О;1<5;1ч<)та[1)[1) = 10<1<-1'; ) ) или графически: ша: 00 01 02 03 04 10 11 12 13 14 20 21 22 23 24 Массив та — это просто 15 целых чисел, к которым мы обращаемся, как если бы здесь были 3 массива по 5 чисел. В частности, в памяти нет единого объекта, который был бы матрицей та — хранятся только элементы.
Размерности 3 и 5 сусцсствуют только в исходном коде. При написании программы наша обязанность — каким-то образом запомнить их. Например, мы могли бы распечатать та следующим образом: иои1ргтг та() 915 В.7. Многомерные массивы /ог (ту! = 0; !<3; !««)( Уог (т1/ = О, У<5;У++) сои1 «та[!) [У] «"ч»; сои! ««чп'; ) Запятую, которая э некоторых языках используется для границ массива, в С+« применять нельзя, поскольку запятая (,) — это оператор последовательности (й 6.2.2).
К счастью, болыпинство ошибок вылавливается компилятором, Например: !и!баб[3, 5); // ошибка: в константных выражениях запятая не допускается т1ьоойг3)Я, //3 массива по 5 левых чисел в каждом т1оисб = упасу[1, 4], //о~иибка: т1, инициализируется т1* Д (увод [1, 4) означает увод[4), то есть !пу«) т1 пасе = довс([1) [4); В.7.3. Передача многомерных массивов Рассмотрим определение функции, которая бы манипулировала двумерной матрицей.
Если размеры известны во время компиляции, проблем не возникает: оо!с(рпп1 т35 [упу т[3)[5]) ( уог (т1! = О; !<3; 1-н-) ( /ог (ул11ыО;1' 5,1ч«) сои! «т[!)[у] «'ч,»; сои1 « "~л'; Трудность возникает, когда нужно передать обе размерности. «Очевидное решение» просто не работает: оо!!Урал! ту (!пут[)[), улуйт1, т1йт2) ( //работает не так, как //большинство людеб могло бы подумать уог (ту! = 0; 1<йту; !ьь) ( /ог [т1 у'= 0 у<йт2 у~-ц) сои1«т[!Щ « "Ч», сои1 « 'чп'; ) // сюрпризу Матрица, представленная как многомерный массив, передается как указатель (а не копируется, 5 5.3).