Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Состояние формата (относится к последнему вопросу, который 24)

Читайте также:
  1. Hasbro Playskool Веселая зверюшка на колесиках – Состояние идеальное, куплена за 650 руб, продаем за 300 батт
  2. I. Современное состояние проблемы
  3. II. Современное состояние и проблемы молодежной политики Российской Федерации
  4. II. Состояние и благосостояние. «Потребность» в опьянении. Ненужное как необходимое. Относительный характер техники.
  5. III. Настоящее состояние (Status prаesens)
  6. III. СОВРЕМЕННОЕ СОСТОЯНИЕ И ПРОБЛЕМЫ РАЗВИТИЯ МОЛОДЁЖИ В РОССИЙСКОЙ ФЕДЕРАЦИИ
  7. Quot;Есть ли между вами такой человек, который, когда сын его попросит у него хлеба, подал бы ему камень?" (Матф. 7:9).

Каждый объект класса из библиотеки iostream поддерживает состояние формата, которое управляет выполнением операций форматирования, например основание системы счисления для целых значений или точность для значений с плавающей точкой. Для модификации состояния формата объекта в распоряжении программиста имеется предопределенный набор манипуляторов.1 Манипулятор применяется к потоковому объекту так же, как к данным. Однако вместо чтения или записи данных манипулятор модифицирует внутреннее состояние потока. Например, по умолчанию объект типа bool, имеющий значение true (а также литеральная константа true), выводится как целая ‘1’:

#include <iostream.h> int main(){ bool illustrate = true; cout << "объект illustrate типа bool установлен в true: " << illustrate << '\n';}

Чтобы поток cout выводил переменную illustrate в виде слова true, мы применяем манипулятор boolalpha:

#include <iostream.h> int main(){ bool illustrate = true; cout << "объект illustrate типа bool установлен в true: "; // изменяет состояние cout так, что булевские значения // печатаются в виде строк true и false cout << boolalpha; cout << illustrate <<'\n';}

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

#include <iostream.h> int main(){ bool illustrate = true; cout << "объект illustrate типа bool: " << illustrate << "\nс использованием boolalpha: " << boolalpha << illustrate <<'\n'; //...}

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

Чтобы отменить сделанную модификацию потока cout, необходимо использовать манипулятор noboolalpha:

cout << boolalpha // устанавливает внутреннее состояние cout << illustrate << noboolalpha // сбрасывает внутреннее состояние cout

Как мы покажем, для многих манипуляторов имеются парные.

По умолчанию значения арифметических типов читаются и записываются в десятичной системе счисления. Программист может изменить ее на восьмеричную или шестнадцатеричную, а затем вернуться к десятичной (это распространяется только на целые типы, но не на типы с плавающей точкой), пользуясь манипуляторами hex, oct и dec:

#include <iostream>int main(){ int ival = 16; double dval = 16.0; cout << "ival: " << ival << " установлен oct: " << oct << ival << "\n"; cout << "dval: " << dval << " установлен hex: " << hex << dval << "\n"; cout << "ival: " << ival << " установлен dec: " << dec << ival << "\n";}

Эта программа печатает следующее:

ival: 16 установлен oct: 20

dval: 16 установлен hex: 16

ival: 10 установлен dec: 16

Но, глядя на значение, мы не можем понять, в какой системе счисления оно записано. Например, 20 – это действительно 20 или восьмеричное представление 16? Манипулятор showbase выводит основание системы счисления вместе со значением с помощью следующих соглашений:

Вот та же программа, но и с использованием showbase:

#include <iostream>int main(){ int ival = 16; double dval = 16.0; cout << showbase; cout << "ival: " << ival << " установлен oct: " << oct << ival << "\n"; cout << "dval: " <<dval << " установлен hex: " << hex << dval << "\n"; cout << "ival: " << ival << " установлен dec: " << dec << ival << "\n"; cout << noshowbase;}

Результат:

ival: 16 установлен oct: 020

dval: 16 установлен hex: 16

ival: 0x10 установлен dec: 16

Манипулятор noshowbase восстанавливает состояние cout, при котором основание системы счисления не выводится.

По умолчанию значения с плавающей точкой выводятся с точностью 6. Эту величину можно модифицировать с помощью функции-члена precision(int) или манипулятора setprecision(); для использования последнего необходимо включить заголовочный файл iomanip. precision() возвращает текущее значение точности. Например:

#include <iostream>#include <iomanip>#include <math.h> int main(){ cout << "Точность: " << cout.precision() << endl << sqrt(2.0) << endl; cout.precision(12); cout << "\nТочность: " << cout.precision() << endl << sqrt(2.0) << endl; cout << "\nТочность:" << setprecision(3) << cout.precision() << endl << sqrt(2.0) << endl; return 0;}

После компиляции и запуска программа печатает следующее:

Точность: 6

1.41421

Точность: 12

1.41421356237

Точность: 3

1.41

Манипуляторы, принимающие аргумент, такие, как setprecision() и setw(), требуют включения заголовочного файла iomanip:

#include <iomanip>

Кроме описанных аспектов, setprecision() имеет еще два: на целые значения он не оказывает никакого влияния; значения с плавающей точкой округляются, а не обрезаются. Таким образом, при точности 4 значение 3.14159 печатается как 3.142, а при точности 3 – как 3.14.

По умолчанию десятичная точка не печатается, если дробная часть значения равна 0. Например:

cout << 10.00

выводит

Чтобы точка выводилась, воспользуйтесь манипулятором showpoint:

cout << showpoint

<< 10.0

<< noshowpoint << '\n';

Манипулятор noshowpoint восстанавливает поведение по умолчанию.

По умолчанию значения с плавающей точкой выводятся в нотации с фиксированной точкой. Для перехода на научную нотацию используется идентификатор scientific, а для возврата к прежней нотации – модификатор fixed:

cout << "научная: " << scientific

<< 10.0

<<"с фиксированной точкой: " << fixed

<< 10.0 << '\n';

В результате печатается:

научная: 1.0e+01

с фиксированной точкой: 10

Если бы мы захотели вместо буквы 'e' выводить 'E', то следовало бы употребить манипулятор uppercase, а для возврата к 'e' – nouppercase. (Манипулятор uppercase не приводит к переводу букв в верхний регистр при печати.)

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

a bc

d

то цикл

char ch;

while (cin >> ch)

//...

читает все буквы от 'a' до 'd' за четыре итерации, а пробельные разделители оператором ввода игнорируются. Манипулятор noskipws отменяет такой пропуск пробельных символов:

char ch;

cin >> noskipws;

while (cin >> ch)

//...

cin >> skipws;

Теперь цикл while будет выполняться семь раз. Чтобы восстановить поведение по умолчанию, к потоку cin применяется манипулятор skipws.

Когда мы пишем:

cout << "пожалуйста, введите значение: ";

то в буфере потока cout сохраняется литеральная строка. Есть ряд условий, при которых буфер сбрасывается (т.е. опустошается), – в нашем случае в стандартный вывод:

// сбрасывает буфер

cout << "hi!" << flush;

// вставляет нулевой символ, затем сбрасывает буфер

char ch[2]; ch[0] = 'a'; ch[1] = 'b';

cout << ch << ends;

// вставляет символ новой строки, затем сбрасывает буфер

cout << "hi!" << endl;

cin.tie(&cout);

Инструкция

cin >>ival;

приводит к сбросу буфера cout.

В любой момент времени объект ostream разрешено связывать только с одним объектом istream. Чтобы разорвать существующую связь, мы передаем функции-члену tie() значение 0:

istream is;

ostream new_os;

 

//...

 

// tie() возвращает существующую связь

ostream *old_tie = is.tie();

 

is.tie(0); // разорвать существующую связь

is.tie(&new_os); // установить новую связь

 

//...

 

is.tie(0); // разорвать существующую связь

is.tie(old_tie); // восстановить прежнюю связь

Мы можем управлять шириной поля, отведенного для печати числового или строкового значения, с помощью манипулятора setw(). Например, программа

#include <iostream>

#include <iomanip>

 

int main()

{

int ival = 16;

double dval = 3.14159;

 

cout << "ival: " << setw(12) <<ival << '\n'

<< "dval: " << setw(12) << dval << '\n';

}

печатает:

ival: 16

dval: 3.14159

Второй модификатор setw() необходим потому, что, в отличие от других манипуляторов, setw() не изменяет состояние формата объекта ostream.

Чтобы выровнять значение по левой границе, мы применяем манипулятор left (соответственно манипулятор right восстанавливает выравнивание по правой границе). Если мы хотим получить такой результат:

- 3

то пользуемся манипулятором internal, который выравнивает знак по левой границе, а значение – по правой, заполняя пустое пространство пробелами. Если же нужен другой символ, то можно применить манипулятор setfill(). Так

cout << setw(6) << setfill('%') << 100 << endl;

печатает:

%%%100

В табл. 20.1 приведен полный перечень предопределенных манипуляторов.

Таблица 20.1. Манипуляторы

Манипулятор Назначение
boolalpha Представлять true и false в виде строк
*noboolalpha Представлять true и false как 1 и 0
Showbase Печатать префикс, обозначающий систему счисления
*noshowbase Не печатать префикс система: счисления
showpoint Всегда печатать десятичную точку
*noshowpoint Печатать десятичную точку только в том случае, если дробная часть ненулевая
showpos Печатать + для неотрицательных чисел
*noshowpos Не печатать + для неотрицательных чисел
*skipws Пропускать пробельные символы в операторах ввода
noskipws Не пропускать пробельные символы в операторах ввода
uppercase Печатать 0X при выводе в шестнадцатеричной системе счисления; E - при выводе в научной нотации
*nouppercase Печатать 0x при выводе в шестнадцатеричной системе счисления; e - при выводе в научной нотации
*dec Печатать в десятичной системе
hex Печатать в шестнадцатеричной системе
oct Печатать в восьмеричной системе
left Добавлять символ заполнения справа от значения
right Добавлять символ заполнения слева от значения
internal Добавлять символ заполнения между знаком и значением
*fixed Отображать число с плавающей точкой в десятичной нотации
scientific Отображать число с плавающей точкой в научной нотации
flush Сбросить буфер ostream
ends Вставить нулевой символ, затем сбросить буфер ostream
endl Вставить символ новой строки, затем сбросить буфер ostream
ws Пропускать пробельные символы
// для этих манипуляторов требуется #include <ionamiip>
setfill(ch) Заполнять пустое место символом ch
Setprecision(n) Установить точность вывода числа с плавающей точкой равной n
setw(w) Установить ширину ноля ввода или вывода равной w
setbase(b) Выводить целые числа по основанию b
* обозначает состояние потока но умолчанию

Переход от С к С++

Преобразование программ, написанных на языке С, в программы на С++. (23 вопрос) Если у вас имеется собственная программа на языке С, возможно она же будет вашей первой программой на С++! Кроме некоторых исключений, язык С является своеобразным подмножеством С++, т.е. С++ поддерживает почти все компоненты С++, дополняя их многими собственными компонентами. Следовательно, начиная работать с С++, можно компилировать программы на С, как и на С++ с помощью компилятора С++ вместо С. Затем можено постепенно добавлять в программы различные компоненты, характерные для С++. Чтобы использовать компилятор С++, нужно присвоить исходному файлу имя с расширением.cpp или.cxx вместо.с. Однако существуют приёмы программирования, допустимые во многих версиях С, которые не будут компилироваться с помощью С++ или будут компилироваться с изменением смысловых значений. Далее описаны некоторые наиболее важные конструкции языка С, которые не поддерживаются в С++. В языке С++ намного больше зарезервированных ключевых слов, чем в С. В программах их нельзя использовать как идентификаторы. Ниже приведён список зарезервированных ключевых слов, который содержит ключевые слова языка С и дополнительные ключевые слова, существующие только в С++.
auto bad_cast bad_typeid bool break case catch char class const const_cast continue default delete do double dynamic_cast else enum except explicit extern false finally float for friend goto if inline int long mutable namespace new operator private protected public register reinterpret_cast return short signed sizeof static static_cast stuct switch template this throw true try type_info typedef typeid typename union unsigned using virtual void volatile while  

В языке С разрешен вызов функции перед её объявлением или определением (в этом случае генерируется предупреждение). Теперь в С++ определение или объявление функции должно предшествовать любому вызову функции внутри исходного файла (в противном случае компилятор сгенерирует ошибку "необъявленный идентификатор").

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

int FuncX (); /* эта функция языка С на самом деле будет использовать несколько параметров */

Однако в языке С++ такое объявление допустимо только для функций, которые не имеют параметров.

В языке С можно использовать "старый стиль" синтаксиса определения функции, в котором типы параметров следуют за списком параметров, например:

int FuncX (A, B); /* правильно в С, ошибка в С++ */int A;int B;{/* код FuncX */return 0;}

В языке С++ использование такого стиля недопустимо.

В некоторых версиях С глобальный объект данных глобальный объект данных можно объявить в программе более одного раза без использования спецификатора extern. В языке С++ для определения переменной можно объявить глобальный объект данных без спецификатора extern только один раз. Чтобы сделать переменную доступной в определённой области видимости, все другие объявления элемента должны включать ключевое слово extern. (Термин область видимости указывает на фрагмент текста программы, в котором используется определённое имя.)

В языке С (в соответствии со стандартом ANSI) можно присвоить указатель типа void указателю любого типа. Например, следующий код задаёт присваивание указателя типа int указателю типа void:

/* этот код правильный в С, но ошибочный в С++ */typedef int TypeA;struct TypeA{ int I; char C; double D; };typedef int TpeB;union TypeB { int I; char C; double D; };typedef int TypeC;enum TypeC (Red, Green, Blue);

В языке С++ присваивание PInt генерирует ошибку, потому что компилятор С++ не будет автоматически преобразовывать указатель типа void в указатель другого типа в выражении присваивания. Для выполнения присваивания используется операция изменения типа.

PInt = (int *)PVoid; /* правильно в С и С++ */

В языке С названия тегов конструкций enum, struct или union могут совпадать с названиями типов данных, определёнными оператором typedef, в пределах одной области видимости. Например, следующий код успешно компилируется в С:

/* этот код правильный в С, но ошибочный в С++ */typedef int TypeA;struct TypeA{ int I; char C; double D; };typedef int TpeB;union TypeB { int I; char C; double D; };typedef int TypeC;enum TypeC (Red, Green, Blue);

Компилятор языка С может различать дублирующие имена, потому что при описании перечислений, структур и объединений используются префиксы enum, struct или union, например:

/* этот код правилен в С, но ошибочен в С++: */typedef int TypeA;struct TypeA { int I; char C; double D; };TypeA X;/* создаёт переменную типа int */struct TypeA Y;/* создаёт структуру TypeA */sizeof (TypeA);/* вычисляет размер переменной типа int */sizeof (struct TupeA);/* вычисляет размер структуры TypeA */

В языке С++ теги конструкций enum, struct, union и class (в С++ их чаще называют именами, а не тегами) должны отличаться от любого имени, заданного в операторе typedef внутри той же области видимости. (Ключевое слово class уникально для языка С++.) Определение создаёт новый тип, на который можно сослаться, используя одно имя этого типа, поэтому не рекомендуется использовать префикс enum, struct, union и class (хотя при желании это можно делать). Описанное свойство продемонстрировано следующим фрагментом программы:

/* этот код ошибочен в С, но правилен в С++ */struct TypeA { int I; char C; double D; };struct TypeA X;/* создаёт структуру TypeA */TypeA Y;/* также создаёт структуру TypeA */sizeof (struct TypeA);/* вычисляет размер структуры TypeAyields */sizeof (TypeA);/* вычисляет размер структуры TypeA */

Следовательно, если задать оператор typedef с таким же именем, то компилятор С++ не всегда сможет различить эти два типа, например:

typedef int TypeAstruct TypeA/* ошибка в С++: повторное определение TypeA */ { int I; char C; double D; };TypeA X;/* создаются при этом данные типа int или структура TypeA? */sizeof (TypeA); /* вычисляется размер данных типа int или размер структуры TypeA? */

Ещё одна несовместимость связана с предыдущей: в языке С, если теги enum, struct или union такие же, как имя, определённое typedef во внешней области видимости, то вы всё ещё можете оставить ссылку на typedef во внутренней области видимости (т.е. имя, определённое typedef, не скрыто). Однако в языке С++ имя typedef должно быть скрыто. Следующий фрагмент программы иллюстрирует различие:

typedef int TypeA;void main () { struct TypeA { int I; char C; double D; }; TypeA X; /* в языке С идентификатор Х имеет тип int; в С++ Х - это структура TypeA */ sizeof (TypeA); /* в С - вычисляет размер данных типа int; в С++ - вычисляет размер структуры TypeA */}

В способах вычисления значений, возвращаемых оператором sizeof, есть два дополнительных различия. Первое: в языке С sizeof ('x') равно sizeof (int), а в С++ оно равно sizeof (char). Далее, предположим, что определено перечисление

enum E {X, Y, Z};

Тогда (второе различие) в С значение sizeof (X) будет равно sizeof (int), а в С++ равно sizeof (E), что не обязательно равно sizeof (int).


Дата добавления: 2015-09-03; просмотров: 124 | Нарушение авторских прав


Читайте в этой же книге: Неполный конструктор | Перезагрузка конструкторов | Перегрузка операций (операторов). Понятие перегрузки операторов. Синтаксис перегрузки операции. Перегрузка бинарных операторов. | Перегрузка операций (операторов). Перегрузка операторов отношения и логических операторов. Перегрузка оператора присваивания. Перегрузка унарных операторов. | Перегрузка операций (операторов). Перегрузка операторов инкремента и декремента. Перегрузка оператора индексирования. Перегрузка оператора вызова функции. | Перегрузка операций (операторов). Перегрузка операторов доступа к членам класса. Перегрузка операторов new и delete. Функции преобразования типа. | Полиморфизм и виртуальные функции. Раннее и позднее связывание. Динамический полиморфизм. Виртуальные функции. Виртуальные и невиртуальные функции. | Полиморфизм и виртуальные функции. Применение динамического полиморфизма. Виртуальные деструкторы. Абстрактные классы и чисто виртуальные функции. | Длина самого длинного слова 10 | Самое длинное слово beautiful |
<== предыдущая страница | следующая страница ==>
Строковые потоки| Работа с несовместимыми конструкциями.

mybiblioteka.su - 2015-2024 год. (0.017 сек.)