Введение в потоки ввода-вывода 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Введение в потоки ввода-вывода



Смешение стилей комментария

В одной и той же программе одновременно могут употребляться комментарии С и С++. В листинге 1.2 приводится несколько таких примеров.

 

 

Листинг 1.2. COMMENTS.CPP (сравнение типов комментариев С и С++)

1: #include <iostream.h>

2:

3: //--------------------------................

4: // Автор: Том Сван

5: // Версия: v1.0

6: // Назначение: Демонстрация комментариев в С++

7; // -

8:

9: main()

10: {

11: cout «"A Brief С++ Commentary\n"; // Вывести заголовок

12: cout «"\n"; // Вывести пустую строку после заголовка
13:

14: /* Этот абзац демонстрирует, что комментарий на языке С может

15: занимать более одной строки.

16: Комментарий на С++ ограничен одной строкой. */
17:

18: cout «"// This is not a comment.\n\n"; // Это комментарий

19:"cout «"/* This also is not comment.*/ \n\n";

20: cout /* Это комментарий. */ «"This text is displayed.\n";

21: return 0; \

22: }

 

 

В интегрированной среде при выделении синтаксиса цвет комментариев очень похож на цвет строчек текста, что делает COMMENTS.CPP трудным для чтения. Для изменения цветов выберите в Option | Environment разделах Syntax Highlighting | Cmtomize, затем Comment из списка Element и щелкните кнопкой мыши на альтернативном цвете переднего плана (FG). (Я использую темно-серый.)

В строках 3~7 используется комментарий С++ для небольшого информационного заголовка, описывающе­го программу. Многие программисты любят "помечать" свои исходные файлы своеобразно стилизованными заголовками, которые могут содержать информацию о программе, исправлениях, дате модификаций и т.п.

Строки 11-12 демонстрируют классический способ завершать операторы на С++ поясняющими коммента­риями. Строки 14-16 содержат многострочный комментарий на ANSI C. Для написания аналогичного коммен­тария на С++ каждую строку следовало бы начинать с / /.

Строки 18-19 иллюстрируют важный принцип: комментарии любого стиля не должны оказаться в середи­не символьной строки. Строка 20 показывает, что только комментарий стиля ANSI C может быть вложен внутрь оператора — прием, приносящий скорее вред, чем пользу, и лучше его избегать.

Введение в потоки ввода-вывода

Поведение объекта потока ввода-вывода очень похоже на стандартный ввод-вывод потоков файлов.

Потоки cout (character out) и cin (character in) имеют множество разнообразных возможностей.

Чтобы отобразить символ с, вы можете написать

cout << с; или

cout.put(c);

Функция put() — член cout, это новое понятие, с которым вы будете часто встречаться в следующих раз­делах.

Для вызова функции-члена, отделите его точкой от cout, как в записи, используемой для доступа к члену структуры. Поток cout — пример класса, который может иметь относящиеся к нему функции, такие, как put(). Вы должны вызывать функ­цию-член только со ссылкой на объект, подобный cout. Без этого выражение

put(c); //??? попытается вызвать независимую функцию put().

Оператор

cout.put(c); вызовет функцию put(), которая принадлежит cout.

Для того чтобы прочитать символ из стандартного ввода, следует использовать поток ввода cin, стоящий перед оператором » (взять из). Оператор

cin» с; читает один символ из стандартного ввода и присваивает его переменной с.

или:

cin.get(c);

Листинг 1.3. FILTER.CPP (простая программа-фильтр на С++)

1: #include <iostream.h> 2:

3: main()

4: {

5: char с; 6:

7: while (cin.get(c))

8: cout.put(c);

9: return 0;

10: }

 
 


Строка 7 в FILTER.CPP вызывает cin.get(c) для ввода символа. Выражение cin.get(c) возвращает значение типа int или нуль при достижении конца источника ввода. Строка 8 передает все символы из источника в стандартный вывод.

Чтение символьных строк

Например, следующее объявление присваивает указателю на строку адрес строки символов

char *s = "Данное";

//Оператор

cout << s;

отправит данную строку но назначению — в системный стандартный поток вывода, обычно на дисплей.

 

Для чтения строки

 

обратите процесс и используйте идентификатор потока ввода cin и оператор » (поместить в)

char buffer[128]; // Объявление буфера

Строки

Cin» buffer; //???

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

Существует более безопасный способ ввести строку, как это показано в листинге 1.5.

Листинг 1.5. GETSTR.CPP (использование потоковой библиотеки для безопасного чтения строк)

1: #include <iostream.h>

2:

3: main()

4: {

5: char s[25];

6: char с;

7:

8: cout << "Enter a 24-char string safely: \n";

9: cin.get(s, 25, '\n');

10: cout «"You entered: " «s «“\n”;

11: if (cin.get(c) && с!= '\n')

12: cout «"Maximum line length reached\n";

13: return 0;

14: }.

 

Функция-член cin.get() вызывается с тремя аргументами.

• Адрес результирующего символьного массива. Строка-результат будет прочитана в этот массив и завершена нулевым символом.

• Размер массива в байтах.

• Символ, завершающий ввод. Если не указан, по умолчанию он равен '\n'.

До тех пор пока вы корректно задаете размер буфера результата, чтение ввода, приведенное в строке 9, безопасно. Одна проблема все же остается. Символ новой строки или другой символ, завершающий ввод, остается в потоке и должен быть прочитан еще одним оператором cin.get(), как это показано в строках 11-12. Если cin.get() не читает символ новой строки, ввод будет усечен. Этот факт необходимо учитывать при написании программ.

Проблему непрочитанного символа новой строки можно решить по-другому: с помощью вызова функции-члена cin.getline(). Для чтения 24-символьной строки в 25-байтовый буфер следует использовать операторы:

char buffer[25]; cin.getline(buffer, 25);

Запись данных

выражение

cout << v;

выведет нечто осмысленное, в системный стандартный поток вывода.

 

Void AnyFunction()


{int count;


// Локальная переменная

}


Область видимости локальной переменной count действует в пределах объявленной функции. В этой функ­ций локальная переменная count делает невозможным доступ к глобальной переменной с тем же именем. Для решения этой проблемы в С++ можно использовать

оператор разрешения области видимости::.

 

Перепишем приведенную выше функцию следующим образом:

 


int count; //Глобальная переменная

void AnyFunction(){

int count; //Локальная переменная

count = 1234; // Присвоить значение локальной переменной

::count = 4321; // Присвоить значение глобальной переменной count

}


 


Теперь она присваивает значение 1234 локальной переменной count и 4321 — глобальной. Выражение::count указывает С++, что используется внешняя переменная count, а не локальная (рис. 1.1).



 


Рис. 1.1. Оператор разрешения области видимости может открыть доступ к скрытой глобальной переменной

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

Листинг 1.8. SCOPE.CPP (использование оператора разрешения видимости)

1: #include <iostream.h>

2:

3: int k = 100; // Глобальная переменная

4: main()

5: {

6: int i = 200; // Локальная переменная

7:

8: cout << "Global k == " << k << \n";

9: cout << "Local i == " << i << '\n';

10:

11: {

12: int к = 300;

13: cout <<Local к *= " << k << '\n';

14: cout «"Global k == " << ::k << '\n';

15: }

16: return 0;

17: }

В строке 3 объявляется и инициализируется значением 100 глобальная переменная k; а в строке 7 объявля­ется переменная i, локальная в функции main(). Строки 9-10 выводят значения k и i.

Нет необходимости ис­пользовать оператор разрешения видимости в строке 9, так как была объявлена только одна переменная k.

Строки 11-15 содержат новый блок-оператор, заключенный внутри функции main(). Хотя это и необычно для практики программирования, блок может быть размещен в другом блоке (строки 11 и 15). Конечно, на практике подобные вложенные блоки принадлежат операторам if, while и им подобным. Внутри вложенного блока в строке 12 объявляется новая переменная с именем k, инициализированная значением 300.

 

В отличие от С, С++ позволяет объявлять и инициализировать переменные в любом месте блока-оператора.

 

Теперь мы имеем две переменных k: глобальную, объявленную в строке 3, и локальную, объявленную в строке 12. Поскольку новая локальная k скрывает глобальную переменную с тем же именем, в строке 13 отображается значение локальной переменной. Чтобы получить доступ к глобальной переменной, используется оператор разрешения области видимости, как показано в строке 14.

 

Void f()

{ for (int i=0; i<MAX; i++)

...

}

Однако такое объявление действует не только в пределах видимости цикла for. Инициализация управляю­щей переменной (в данном случае i=0;) выполняется до того, как начнется цикл, таким образом, i в данном примере нопадает в область видимости f() и может использоваться любыми операторами, следующими за for.

 

Константы

 

Константы — новшество языка С++, заимствованное языком C.

Объявление переменных с ключевым словом const создает вокруг них "силовое поле", предохраняющее их от изменения во время выполнения про­граммы.

 

ПРИМЕР: Если вы объявили целую переменную count следующим образом:

const int count =1234;

Компилятор выдаст сообщение об ошибке в операторе

count++; //???

Некоторые программисты рекомендуют использовать объявления const вместо символьных констант, соз­данных с помощью #define.

Символьная константа

#define МАХ 100

определяет макрос с именем МАХ, связанный с текстом 100 (не целым значением 100).

Если МАХ использу­ется следующим образом:

for (int i=0; i<MAX; i++)

то компилятор заменит МАХ на текстовые цифры 100 и скомпилирует оператор так, как будто вы ввели эти цифры в этом месте.

Некоторые эксперты по С++ утверждают, что легко сделать ошибку при использовании символьных кон­стант, подобных МАХ. Сторонники объявления const скорее предложат вам следующее:

const int MAX = 100;

Цикл for останется таким же, а объявление МАХ истинной константой даст определенные преимущества.

• Компилятор сможет выполнить проверку типов с МАХ более строго. С++ распознает, что константа МАХ
имеет тип int, в то время как компилятор ничего не знает о типе текстового макроса МАХ.

• Turbo Debugger распознает истинную константу МАХ. Отладчикне распознает символьные константы, созданные с помощью #define.

Все это необходимо иметь в виду. К несчастью, истинная константа МАХ нуждается в постоянном месте хранения в сегменте данных программы. Многочисленные программные константы могут занимать сотни ты­сяч байтов, расходуя тем самым память. Более того, использование таких значений может потребовать отни­мающих время обращений к памяти.

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

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

 

Их преимущества не настолько велики, чтобы совсем отказываться от #define.

Встраиваемые функции

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

Хотя вызов функции происходит быстрее, чем вы успеете глазом моргнуть, мно­гочисленные вызовы могут ухудшить общее быстродействие программы. Полный отказ от функций — непри­емлемое решение этой проблемы! Функции делают программу модульной и более легкой для поддержки. Без функций исключительно сложно, может быть, невозможно написать даже среднюю по размерам корректно ра­ботающую программу.

С другой стороны, разворачивание циклов и устранение многочисленных вызовов функций — стиль, сбе­регающий время и улучшающий общее быстродействие программы.

Рассмотрим следующий гипотетический цикл for:

for (int i = 0; i < MAX; i++) { AnyFunction();

...

}

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

void AnyFunction(void)

{

cout «AnyValue «'\n';

AnyValue++;

...

}

Все это, конечно, предположительно, но один факт не вызывает сомнений: вставка тела AnyFunction() не­посредственно в цикл for ускорит выполнение программы:

for (int i = 0; i <MAX; i++)

{cout << AnyValue << '\n'; AnyValue++;

...

}

Альтернативно можно объявить функции inline (встраиваемыми), вставляя тем самым их тела в поток кода. Как это сделать, показано в листинге 1.9.

Листинг 1.9. INLINE.CPP (демонстрация встраиваемых функций)

 


1: #include < iostream.h>
2:    
3: inline int max(int a, int b)
4: {  
5: if (a >= b)
6: return a;  
7: else  
8: return b;  
9: }  
10:    
11: main()  
12: {  
13: int x, y, z;
14:    
15: cout << " X? ";
16: cin >> x;  
17: cout << " Y? ";
18: cin >> y;  
19: z = max(x , y);
20: cout << " max(a, b) == " << z << ' \n';
21: return 0;  
22: }  

Для того чтобы объявить функцию встраиваемой, напишите перед ней ключевое слово inline, как показано в строке 3. Пишется функция как обычно (строки 4-9). Ничего необычного в ее содержимом нет — все, что выполняется в любой функции, выполнится и для объявленной встраиваемой. Обычно встраиваемые функ-ции.подобные той, что определена в строках 3-9, объявляются в заголовочных файлах и включаются в каж­дый модуль, где необходимо их использование. Встраиваемую функцию необходимо полностью определить до того, как можно будет ее использовать, и включение ее текста в заголовочный файл — самый простой способ удовлетворения этого требования.

Используйте встраиваемые функции в точности так же, как вы используете обычные. Например, в строке 19 вызывается max() для определения большего из двух целых чисел с присвоением этого значения переменной z. Конечно, в скомпилированном коде Borland C++ не вызывает функцию max() в строке 19. Вместо этого компи­лятор вставляет тело функции непосредственно в программу, компилируя строку 19, как если бы она была напи­сана следующим образом:

if (x >= у)

z = x;

else z = у;

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

 

Встраиваемые функции сродни регистровым переменным. Когда вы объявляете встраиваемую функцию, вы лишь даете указание компилятору, и, если возможно, тело функции будет вставлено прямо туда, откуда эта функция вызывается. Разумеется, компилятор — не золотая рыбка, и нет гарантии, что так будет с каждой вашей командой. Если встраиваемый код, к примеру, слишком велик, то компилятор может отказаться вставить функцию в поток кода, и вместо этого сгенерирует обычный вызов. Также при компиляции программ для Turbo Debugger все встраиваемые функции будут преобразованы в обычные вызываемые функции, которые можно будет отлаживать. Хорошие программы на С++ работают корректно вне зависимости от того, как скомпилированы в них встраиваемые функции.


Управление памятью с помощью new и delete

Функ­ции malloc(), farmalloc(), farcalloc(), free(), farfree() и другие одинаково доступны для всех программ на С и С++.

Однако С++ предлагает альтернативные операторы управления памятью new и delete, которые могут делать то же самое, что и стандартные функции, и более того.

Используйте new для выделения памяти динамическим переменным. Используйте free, чтобы освободить память, выделенную new, для ее использования в последующих операторах new.

new и deleteунарные операторы, а не функции. Использование этих операторов вместо стандартных функций управления памятью дает возможность при необходимости са­мостоятельно обрабатывать ситуации управления памятью.

Чтобы выделить память для переменной, имеющей тип double, и присвоить ее адрес указателю, вы можете написать

double *dp = new double;

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

double *dp = new(double);

Это не так, и лишние круглые скобки просто игнорируются. Используется dp так же, как и любой другой ука­затель на память, выделенную malloc() или подобной функцией.

Для присваивания значения содержимому памяти, адрес которой хранится в dp,

*dp = 3.14159;

Закончив использование динамической переменной, удалите ее следующим образом:

delete dp;

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

Для освобождения памяти, выделенной с помощью new, необходимо использо­вать только delete. Динамические переменные, созданныефункцией malloc(), следует уничтожать с помощью функции free() (или, возможно, farfree()). Вы можете использовать malloc() и new в одной и той же про­грамме, но вы не можете смешивать способы управления памятью С и С++.

Main()

10:{

11: struct q *qp; // Указатель на структуру q

12:

13: set_new_handler(0); // Указание new вернуть 0 в случае неудачи

14: for (;;) { // Повторять следующий оператор "без конца"

15: qp = new q; // Выделить новую структуру типа q

16: cout «qp«'\n'; // Вывести адрес структуры

17: if (qp == 0) { // В случае возврата new 0 следует:

18: cout «"Out of memory\n"; // Вывести сообщение об ошибке

Define SIZE 80

4:

Main()

6: {

7: char *sp;

8:

9: sp = new char[SIZE];

10: cout «"String?";

11: cin.getline(sp, SIZE);

12:' cout «"You entered:" «sp «'\n';

13: delete[] sp;
14: return 0;

15: }

Строка 9 вьщеляет символьный массив размером SIZE в байтах и присваивает адрес первого байта этого мас­сива sp. Строки 10-12 демонстрируют использование динамических строк, запрашивая и выводя строку текста.

Строка 13 удаляет динамический символьный массив. Borland С++ разрешает написать этот оператор без скобок следующим образом:

delete sp; //???, но безопасно в Borland C++

Следуя более строгому протоколу С++, необходимо использовать пустые скобки в выражении delete[], указывающие компилятору, что удаляется массив, а не простая переменная. (В Borland C++ скобки необходи­мы только в том случае, если удаляется массив классовых объектов, но об этом позже.)

В ранних версиях С++ при удалении массива нужно было указывать количество элементов. В С++ вер­сии 2.0, например, строка 15 имела бы вид delete[SIZE] sp;. Borland С++ игнорирует SIZE в таком случае и выдает предупреждение о попытке использовать устаревшую форму delete.

Перегрузка функций

Пример: программа, которая должна рисовать не­сколько различных фигур. Каждая функция прорисовки имеет свое собственное имя, что делает код "усыпан­ным" функциями типа DrawEllipse, DrawCircle, DrawSquare, DrawLine и т.д мы получим программу, словно написанную заикой:

DrawEllipse(ellipse); DrawCircle(circle); DrawSquare(square); DrawLine(line);

Не будет ли лучше, если вы используете одно и то же имя функции (назовем ее Draw) для вывода всех фигур?

Draw(ellipse); Draw(circle); Draw(square); Draw(line);

В С++ многочисленные функции могут иметь одинаковое имя до тех пор, пока они отличаются хотя бы одним параметром. Функции "перегружены", поскольку их имена одинаковы, а выполняемая ими работа — различна.

Многие функции Draw в нашей гипотетической графической программе остаются раздельными и различными, и написаны точно так же, как и другие не перегруженные функции. Но компилятор С++ распознает их по тому, как они используются, а не только по их именам.

Пример: В листинге 1.13 ис­пользуются перегруженные функции для отображения квадратов трех различных значений.

Листинг 1.13. OVERLOAD.CPP (перегрузка функций)

1:#include <iostream.h>

2:

3:int square(int а);

4:double square(double а);

5:long double square(long double a);

6:

Main()

8:{

9: int x = 10;

10 double у = 20.5;

11 long double z = 30.75;

12:

13: cout << square(x) << '\n';

14: cout << square(y) << '\n';

15: cout << square(z) << '\n';

16: return 0;

17: }
18:

19:int square(int а)

20:{

21: return а * а;

22: }
23:

24:double square(double а)

25:{

26: return а * а;

27: }
28:

29:long double square(long double a)

30:{

31: return а * а;

32: }

Прототипы трех перегруженных функции square() определены в строках 3-5. Все функции имеют одина­ковое имя, но, тем не менее, они различны, поскольку каждая из них отличается хотя бы одним параметром от другой. Сами функции реализованы в строках 19-32 как раздельные, т.е. имеющие различные имена.

В строках 13-15 показано, как перегруженные функции могут прояснять суть программы. Несмотря на различия в типах данных, очевидно, что каждый оператор выводит квадрат аргумента. Это куда более прият­но, чем различать функции по именам типа squareInt(), squareDouble() и squareLongDouble(). Конечно, ре­шать, стоит ли перегружать функции, которые выполняют более или менее схожую работу, придется вам. Ес­ли вы назовете все функции в вашей программе одним и тем же именем (с учетом того, что они должны от­личаться хотя бы одним своим аргументом), то ваш код может стать совершенно непостижимым, как новелла, представляющая собой многократное повторение одного и того же слова.

Ссылки

int i = 1234;

int *p = &i;

объявляется целая переменная i, инициализированная значением 1234, и указатель на целое p, адресующий i.

В соответствии с этими объявлениями следующие два оператора выводят значение i:

cout << "i == " << i << '\n';

cout <<"i == " << *p <<'\n';

Выражение *p указывает компилятору, что следует использовать значение, адресуемое р.

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

С++ предлагает альтернативу для более безопасного доступа к переменным через указатели. Объявив ссы­лочную переменную, вы создадите объект, который, как указатель, ссылается на другое значение, но, в от­личие от указателя, постоянно привязан к своему alter ego ("второму я"). Ссылка на значение всегда ссылает­ся на это значение.

Ссылки, в основном, используются в качестве переменных, параметров функций и результатов функций.

Main()

4: {

5: int ivar = 1234;

// Переменной присвоено значение

6: int *iptr = &ivar;

// Указателю присвоен адрес ivar

7: int &iref = ivar;

// Ссылка ассоциирована с ivar

8: int *p = &iref;

// Указателю присвоен адрес iref

9:

10: cout «"ivar == " «ivar «'\n';

11: cout «"*iptr == " «*iptr «'\n';

12: cout «"iref == " «iref «'\n';

13: cout «"*p == " << *p «'\n';

14: return 0;

15:}


 

В строках 5-8 объявляются четыре переменные. Первая — простое целое ivar, инициализированное значением 1234. Следующая, — указатель на целое с именем iptr, которой присвоен адрес ivar. Третья объяв­лена как ссылочная переменная. Строка

int &iref = ivar;

объявляет iref как ссылку на целое значение. Что касается iref, то ей присваивается ivar не как значение пере­менной, а как адрес в памяти. Следуя объявлению, iref указывает на ivar подобно указателю. Как показано в строке 12, оператор

cout «"iref == " «iref «'\n';

выводит значение ivar — 1234. Это происходит благодаря использованию iref в качестве ссылки на местополо­жение переменной ivar в памяти.

Четвертое объявление в строке 8 создает еще один указатель — p, которому присваивается адрес, храня­щийся в iref. Строки 6 и 8 дают одинаковый результат. В обеих строках создаются указатели, ссылающиеся на ivar. Как показано в строке 13, употребление указателя в выражении *p дает доступ к значению ivar. На рис. 1.2 проиллюстрирована взаимосвязь переменных из листинга 1.15. Как видно из иллюстрации, исполь­зование iref очень похоже на использование разыменования указателя *p. В обоих выражениях осуществляет­ся доступ к значению ivar — 1234.

Рис. 1.2. Взаимосвязь переменных в листинге 1.15, REFVALCPP

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

 

В REFVAL.CPP вы не можете объявить новую целочисленную переменную и при­своить ее адрес iref:

int anotherInt;

iref = anotherInt; //???

Это присваивание не заставит iref ссылаться на anotherInt. Это выражение присвоит значение anotherInt объекту, на который iref ссылается, другими словами — ivar. Так же вы можете присваивать новые значения объекту, к которому относится ссылка. Например, выражение

iref = 4321;

присвоит ivar значение 4321. Эти правила будет легче запомнить, если представить себе ссылки как неизме­няемые альтернативные имена, похожие на указатели (но не идентичные им!).

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

int &iref; //???

 

В отличие от указателей, которые могут быть объявлены в неинициализированном состоянии или установ­лены в нуль (если указатель не ссылается на необходимые данные), ссылки всегда ссылаются на объект. Для ссылок не существует аналога нулевого указателя.

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

 

Не существует операторов, непосредственно производящих действия над ссылками. Все операции соверша­ются только над соответствующими объектами.

 

Добавьте между строками 13 и 14 листинга 12.15 следующий оператор:

iref++;

Компилятор сгенерирует код, инкрементирующий ivar — переменную, на которую ссылается iref. Оператор не совершит никаких действий непосредственно над iref.

 

Ссылки также могут ссылаться на константы.

 

Разумеется, вы не можете присвоить значение непосредст­венно ссылке. Объявление

int &iref = 1234; //???

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

int x = 1234; // Объявление и инициализация целочисленного объекта

const int &iref = x; // Объявление iref как константной ссылки на x

Этот прием очень полезен, поскольку эффективно превращает переменную в константу, которую нельзя подвергнуть изменениям. Например, вы можете записать значение x в выходной поток с помощью ссылки сле­дующим образом:

cout << "iref = " << iref << '\n'; // Все в порядке

Вы также можете изменить значение переменной x:

x = 4321; // Тоже годится

Поскольку iref — константа, то вы, конечно, не сможете присвоить новое значение x через ссылку:

iref = 4321; //??? Нельзя

Попытка скомпилировать последнее выражение приведет к выдаче сообщения об ошибке "Cannot modify a const object in function main()" (Нельзя изменить константный объект в функции main()).

Смешение стилей комментария

В одной и той же программе одновременно могут употребляться комментарии С и С++. В листинге 1.2 приводится несколько таких примеров.

 

 

Листинг 1.2. COMMENTS.CPP (сравнение типов комментариев С и С++)

1: #include <iostream.h>

2:

3: //--------------------------................

4: // Автор: Том Сван

5: // Версия: v1.0

6: // Назначение: Демонстрация комментариев в С++

7; // -

8:

9: main()

10: {

11: cout «"A Brief С++ Commentary\n"; // Вывести заголовок

12: cout «"\n"; // Вывести пустую строку после заголовка
13:

14: /* Этот абзац демонстрирует, что комментарий на языке С может

15: занимать более одной строки.

16: Комментарий на С++ ограничен одной строкой. */
17:

18: cout «"// This is not a comment.\n\n"; // Это комментарий

19:"cout «"/* This also is not comment.*/ \n\n";

20: cout /* Это комментарий. */ «"This text is displayed.\n";

21: return 0; \

22: }

 

 

В интегрированной среде при выделении синтаксиса цвет комментариев очень похож на цвет строчек текста, что делает COMMENTS.CPP трудным для чтения. Для изменения цветов выберите в Option | Environment разделах Syntax Highlighting | Cmtomize, затем Comment из списка Element и щелкните кнопкой мыши на альтернативном цвете переднего плана (FG). (Я использую темно-серый.)

В строках 3~7 используется комментарий С++ для небольшого информационного заголовка, описывающе­го программу. Многие программисты любят "помечать" свои исходные файлы своеобразно стилизованными заголовками, которые могут содержать информацию о программе, исправлениях, дате модификаций и т.п.

Строки 11-12 демонстрируют классический способ завершать операторы на С++ поясняющими коммента­риями. Строки 14-16 содержат многострочный комментарий на ANSI C. Для написания аналогичного коммен­тария на С++ каждую строку следовало бы начинать с / /.

Строки 18-19 иллюстрируют важный принцип: комментарии любого стиля не должны оказаться в середи­не символьной строки. Строка 20 показывает, что только комментарий стиля ANSI C может быть вложен внутрь оператора — прием, приносящий скорее вред, чем пользу, и лучше его избегать.

Введение в потоки ввода-вывода

Поведение объекта потока ввода-вывода очень похоже на стандартный ввод-вывод потоков файлов.

Потоки cout (character out) и cin (character in) имеют множество разнообразных возможностей.

Чтобы отобразить символ с, вы можете написать

cout << с; или

cout.put(c);

Функция put() — член cout, это новое понятие, с которым вы будете часто встречаться в следующих раз­делах.

Для вызова функции-члена, отделите его точкой от cout, как в записи, используемой для доступа к члену структуры. Поток cout — пример класса, который может иметь относящиеся к нему функции, такие, как put(). Вы должны вызывать функ­цию-член только со ссылкой на объект, подобный cout. Без этого выражение

put(c); //??? попытается вызвать независимую функцию put().

Оператор

cout.put(c); вызовет функцию put(), которая принадлежит cout.

Для того чтобы прочитать символ из стандартного ввода, следует использовать поток ввода cin, стоящий перед оператором » (взять из). Оператор

cin» с; читает один символ из стандартного ввода и присваивает его переменной с.

или:

cin.get(c);

Листинг 1.3. FILTER.CPP (простая программа-фильтр на С++)

1: #include <iostream.h> 2:

3: main()

4: {

5: char с; 6:

7: while (cin.get(c))

8: cout.put(c);

9: return 0;

10: }

 
 


Строка 7 в FILTER.CPP вызывает cin.get(c) для ввода символа. Выражение cin.get(c) возвращает значение типа int или нуль при достижении конца источника ввода. Строка 8 передает все символы из источника в стандартный вывод.



Поделиться:


Последнее изменение этой страницы: 2016-08-01; просмотров: 284; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 54.224.90.25 (0.256 с.)