extracted_text:
тема 2 вопрос 32
структура программы в c++ примеры
Структура программы на языке С++.
Выглядит схема примерно так:
Подключаемые внешние файлы (*.h, *.cpp)
Обьявление глобальных переменных и функций
int main(список аргументов)
{
последовательность операторов
}
тип_возвращаемого_значения имя_функции (список входных параметров)
{
последовательность операторов
}
Этой схеме можно привести простейший пример на C++:
#include
int main(int argc, char* argv[])
{
// тело функции
return 0;
}
int& min(int& a, int& b)
{
if (a>b)
return a;
return b;
}
Программа на языке С++ может состоять из одной и более функций,
но функция ... main( ... ) должна быть только одна.
Именно с этой функции начинается выполнение программы, поэтому, при отсутствии ( или в наличии
более чем один экземпляр ) такой функции
компилятор выдаст соответствующее сообщение об ошибке.
Еще такое замечание, в С и С++ любая последовательность операторов заканчивается ';'  символом
точка с запятой,
поэтому будьте внимательны, когда набираете программу, если забудете поставить  компилятор
выдаст сообщение об ошибке: в строке такой то нехватает символа ';'.
Комментарии в программе пишутся после " // " или между " /* ... */ ". В первом случае их размер не
должен превышать размера строки, во втором размер неограничен.
2. Структура программы
Программа на языке С++ состоит из директив препроцессора, указаний компилятору, объявлений
переменных и/или констант, объявлений и определений функций.
2.1. Объявление переменной
Объявление переменной задаёт имя и атрибуты переменной. Атрибутами переменной могут быть тип,
количество элементов (для массивов), спецификация класса памяти, а также инициализатор.
Инициализатор – это константа соответствующего типа, задающая значение, которое присваивается
переменной при создании.
Объявление переменной имеет следующий синтаксис: [<спецификация класса памяти>]
<тип> <имя> [= <инициализатор>] [,<имя> [= <инициализатор>] ...];
Примеры объявления переменных
int x;
double y = exp(1);
// Объявление переменной целого типа без
инициализатора
// Переменная вещественного типа инициализируется
числом e. // exp(x) – функция, вычисляющая ex. int a, b = 0;
// Объявление двух переменных целого типа.
Переменная b инициализируется значением 0.
В языке С++ нет ограничений на количество символов в имени. Однако некоторые части
реализации (в частности, компоновщик) недоступны автору компилятора, и они иногда
накладывают такие ограничения.
2.1.1. Константы
В языке С++ введена концепция определяемых пользователем констант для указания на то,
что значение нельзя изменить непосредственно. Это может быть полезно в нескольких
отношениях. Например, многие объекты не меняются после инициализации; использование
символических констант приводит к более удобному в сопровождении коду, чем
применение литералов непосредственно в тексте программы; указатели часто
используются только для чтения, но не для записи; большинство параметров функций
читаются, но не перезаписываются.
Чтобы объявить объект константой, в объявление нужно добавить ключевое слово const.
Так как константе нельзя присваивать значения, она должна быть инициализирована.
const int a = 100; const int b[] = {1, 2,
3, 4, 5}; const int c;
// a является константой // Все b[i] являются
константами // Ошибка – нет инициализатора!
Типичным является использование констант в качестве размера массивов и меток в
инструкции case.
Отметьте, что const модифицирует тип, т.е. ограничивает возможное использование
объекта, но не указывает способ размещения константного объекта. Простым и типичным
использованием константы является тот случай, когда значение константы известно во
время компиляции и под неё не требуется выделение памяти. Для массива констант, как
правило, требуется выделение памяти, так как, в общем случае, компилятор не в состоянии
определить, к какому элементу массива происходит обращение в выражении.
2.1.2. Объявление typedef
Объявление, начинающееся с ключевого слова typedef, вводит новое имя для типа, не для
переменной данного типа. Целью такого объявления часто является назначение короткого
синонима для часто используемого типа. Например, при частом применении unsigned char
можно ввести синоним uchar.
typedef unsigned char uchar;
// Теперь uchar – синоним для unsigned char
Имена, вводимые с помощью typedef, являются синонимами, а не новыми типами.
Следовательно, старые типы можно использовать совместно с их синонимами. Если вам
нужны различные типы с одинаковой семантикой или с одинаковым представлением,
обратитесь к перечислениям или классам.
2.2. Объявление и определение функции
Объявление функции задаёт имя функции, тип возвращаемого значения и количество и
типы параметров, которые должны присутствовать при вызове функции. Указание void в
качестве возвращаемого значения означает, что функция не возвращает значения.
Определением функции является объявление функции, в котором присутствует тело
функции. Определение функции имеет следующий синтаксис:
<тип> <имя> (<список формальных параметров>) { [<объявления>] [<операторы>] }
Типы в определении и объявлениях функции должны совпадать. Однако, имена параметров
не являются частью типа и не обязаны совпадать.
Все функции в программе существуют на глобальном уровне и не могут быть
вложены друг в друга.
Среди функций выделяется одна главная функция, которая должна иметь имя main. С нее
начинается выполнение программы, обычно она управляет выполнением программы, организуя вызовы других функций. Для того чтобы программа могла быть скомпилирована
и выполнена, она должна содержать, по крайней мере, определение функции main.
Примеры определения функции
double Cube(double x);
void main() { printf("%lf\n",
Cube(5)); }
double Cube(double x) { return x * x *
x; }
// // Объявление (прототип) функции
// Главная функция программы, которая печатает 53
// Функция одного вещественного аргумента, которая
возвращает вещественное значение, // равное кубу
аргумента
При вызове функции выделяется память под её формальные параметры, и каждому
формальному параметру присваивается значение соответствующего фактического
параметра. Семантика передачи параметров идентична семантике инициализации. В
частности, проверяется соответствие типов формальных и фактических параметров и при
необходимости выполняются либо стандартные, либо определённые пользователем
преобразования типов. Существуют специальные правила для передачи массивов в
качестве параметров, средства для передачи параметров, соответствие типов для которых
не проверяется, и средства для задания параметров по умолчанию.
Функция должна возвращать значение, если она не объявлена как void. И наоборот –
значение не может быть возвращено из функции, если она объявлена как void. Как и
передача параметров, семантика возврата значения из функции идентична семантике
инициализации. Возвращаемое значение задаётся инструкцией return.
int  f1() { } void f2() { }
int f3() { return 1; } void f4() { return
1; }
int  f5() { return; } void f6() { return; } // Ошибка – не указано возвращаемое значение //
// Ошибка – не возвращается значение // Правильно
// Правильно // Ошибка – значение возвращается в
функции void
Правильно
Функция с типом void не может возвращать значение. Однако вызов функции с типом void
не даёт значения, так что функция с типом void может использовать вызов функции с
типом void как выражение в инструкции return.
void g() { ... } void h() { return g(); } // Правильно
Такая форма инструкции return важна при написании шаблонов функций, когда тип
возвращаемого значения является параметром шаблона.
2.2.1. Встраиваемые функции
Функцию можно определить со спецификатором inline. Такие функции называются
встраиваемыми. Спецификатор inline указывает компилятору, что открытая подстановка
тела функции предпочтительнее обычной реализации вызова функции и что он должен
пытаться каждый раз генерировать в месте вызова код, соответствующий встраиваемой
функции, а не создавать отдельно код функции (однократно) и затем вызывать её
посредством обычного механизма вызова. Спецификатор inline не оказывает влияния на
смысл вызова функции.
inline int max(int x, int y) { return x > y ? x : y; }
Открытая подстановка не влияет на результаты вызова функции, чем отличается от
макроподстановки. Встраиваемая функция имеет обычный синтаксис описания функции и
подчиняется всем правилам, касающимся области видимости и контроля типов. Открытая
подстановка является просто иной реализацией вызова функции. Вместо генерации кода,
передающего управление и параметры единственному экземпляру тела функции, копия тела функции, соответственно модифицированная, помещается на место вызова. Это
экономит время для передачи управления.
Для всех, кроме простейших, функций время выполнения функций доминирует над
издержками времени на обслуживание вызова. Из этого следует, что для всех, кроме
простейших, функций экономия за счёт открытой подстановки минимальна. Идеальным
кандидатом для открытой подстановки является функция, делающая нечто простое, вроде
увеличения или возврата значения. Существование таких функций вызывается
необходимостью обработки скрытых данных.
2.2.2. Параметры функций по умолчанию
В языке С++ можно задавать так называемые параметры функции по умолчанию. Если в
объявлении формального параметра задано выражение, то оно воспринимается как
умолчание этого параметра. Все последующие параметры также должны иметь умолчания.
Умолчания параметров подставляются в вызов функции при отсутствии в нём последних
по списку параметров.
int g(int m = 1, int n); int h(int m = 1,
int n = 2); int h(int m = 1, int n = 2)
{ ... } int h(int m = 0, int n = 0) { ... }
int f(int m = 1, int n = 2); int f(int m ,
int n) { ... } f(5, 6); f(5); f();
// Ошибка // Правильно // Ошибка – повтор параметров
по умолчанию // Ошибка – изменение параметров по
умолчанию // Правильно // Вызов функции с двумя
параметрами // Эквивалентно вызову f(5, 2); //
Эквивалентно вызову f(1, 2);
2.2.3. Параметры программы
Функция main, как и любая другая функция может иметь параметры. Эти параметры
передаются в программу из командной строки.
void main(int argc, char *argv[]) { ... } // Имена argc и argv не являются требованием языка
Первый параметр содержит количество элементов в массиве – втором параметре, который
является массивом указателей на строки. Каждая строка хранит один переданный
программе параметр, при этом первый параметр (с индексом 0) содержит имя
исполняемого файла и существует всегда. Порядок объявления параметров существенен.
2.2.4. Функции с переменным числом параметров
В языке С++ существует возможность использовать функции с переменным числом
параметров. Для объявления такой функции надо указать многоточие (,…) в конце списка
параметров функции. Для вызова такой функции не требуется никаких специальных
действий, просто задается столько параметров, сколько нужно.
Во время интерпретации списка параметров такая функция пользуется информацией, не
доступной компилятору. Поэтому он не в состоянии гарантировать, что ожидаемые
параметры действительно присутствуют или что они имеют правильные типы. Ясно, что
если параметр не был объявлен, компилятор не имеет информации, необходимой для
выполнения стандартной проверки и преобразований типа.
Функцию только с необъявленными параметрами, в принципе, определить можно, но
выбрать параметры будет затруднительно, т.к. макроопределения для работы с
необъявленными параметрами используют имя последнего объявленного формального
параметра.
Внутри функции программист сам отвечает за выбор из стека дополнительных параметров.
Для работы с ними используются макроопределения va_arg, va_start и va_end,
определённые в файле stdarg.h.
Пример программы с функцией с перменным числом параметров см. в конце лекции.
2.3. Препроцессор
Препроцессор – это программа, которая обрабатывает текст вашей программы до
компилятора. Таким образом, на вход компилятора попадает текст, который может
отличаться от того, который видите Вы. Работа препроцессора управляется директивами.
С помощью препроцессора можно выполнять следущие операции: включение в программу текстов из указанных файлов;
замена идентификаторов последовательностями символов;


 макроподстановка, т.е. замена обозначения параметризованным текстом,
формируемым препроцессором с учетом конкретных аргументов;
исключение из программы отдельных частей текста (условная компиляция).

2.3.1. Включение файлов
Включение файлов производиться с помощью директивы #include, которая имеет
следующий синтаксис:
#include <путь> #include "путь"
Угловые скобки здесь являются элементом синтаксиса.
Директива #include включает содержимое файла, путь к которому задан, в компилируемый
файл вместо строки с директивой. Если путь заключен в угловые скобки, то поиск файла
осуществляется в стандартных директориях. Если путь заключен в кавычки и задан
полностью, то поиск файла осуществляется в заданной директории, а если путь полностью
не задан – в текущей директории. С помощью это директивы Вы можете включать в текст
программы как стандартные, так и свои файлы.
Во включаемый файл можно поместить, например, общие для нескольких исходных файлов
определения именованных констант и макроопределения. Включаемые файлы
используются также для хранения объявлений внешних переменных и абстрактных типов
данных, разделяемых несколькими исходными файлами. Более подробную информацию об
использовании заголовочных файлов см. в лекции 9.
Кроме того, как было указано выше, в языке С++ ряд функций, такие как функции
ввода/вывода, динамического распределения памяти и т.д., не являются элементом языка, а
входят в стандартные библиотеки. Для того чтобы пользоваться функциями стандартных
библиотек, необходимо в текст программы включать так называемые заголовочные файлы
(в описании каждой функции указывается, какой заголовочный файл необходим для неё).
Это также делается с помощью директивы препроцессора #include.
Директива #include может быть вложенной. Это значит, что она может встретиться в
файле, включенном другой директивой #include. Допустимый уровень вложенности
директив #include зависит от реализации компилятора.
2.3.2. Макроподстановки
Макроподстановки реализуются директивой #define, которая имеет следующий синтаксис:
#define <идентификатор> <текст> #define <идентификатор>(<список параметров>)
<текст>
Директива #define заменяет все вхождения идентификатора в исходном файле на текст,
следующий в директиве за идентификатором. Этот процесс называется
макроподстановкой. Идентификатор заменяется лишь в том случае, если он представляет
собой отдельную лексему. Например, если идентификатор является частью строки или
более длинного идентификатора, он не заменяется.
Текст представляет собой набор лексем, таких как ключевые слова, константы,
идентификаторы или выражение. Один или более пробельных символов должны отделять
текст от идентификатора (или от заключённых в скобки параметров). Если текст не
умещается на строке, то он может быть продолжен на следующей строке, для этого
следует набрать в конце строки символ «обратный слэш» и сразу за ним нажать клавишу
«ВВОД».
Текст может быть опущен. В этом случае все экземпляры идентификатора будут
удалены из исходного текста программы. Тем не менее, сам идентификатор
рассматривается как определённый.
Список параметров, если он задан, содержит один или более идентификаторов,
разделённых запятыми, и должен быть заключён в круглые скобки. Идентификаторы в
списке должны отличаться друг от друга. Их область действия ограничена
макроопределением, в котором они заданы. Имена формальных параметров в тексте
отмечают позиции, в которые должны быть подставлены фактические аргументы
макровызова. В макровызове следом за идентификатором записывается в круглых скобах список
фактических аргументов, соответствующих формальным параметрам из списка
параметров. Списки фактически и формальных параметров должны содержать одно и то
же количество элементов. Не следует путать подстановку аргументов в
макроопределение с передачей аргументов функции. Подстановка в препроцессоре
носит чисто текстовый характер. Никаких вычислений или преобразований типа при
этом не производится.
После того как выполнена макроподстановка, полученная строка вновь просматривается
для поиска других имен макроопределений. При повторном просмотре не принимается к
рассмотрению имя ранее произведенной макроподстановки. Поэтому директива #define x x
не приведет к зацикливанию препроцессора.
Примеры
#define N 100 #define MULT(a, b) ((a) * (b)) #define MAX(x, y) ((x) > (y)) ? (x) : (y)
Вызов MULT(x + y, z) будет заменен на ((x + y) * (z)). При отсутствии внутренних скобок
получилось бы (x + y * z), что неверно.
Макровызов MAX(i, a[i++]) заменится на ((i) > (a[i++])) ? (i) : (a[i++])). Результат
вычисления непредсказуем.
В директиве #define две лексемы могут быть «склеены» вместе. Для этого их нужно
объединить знаками ## (слева и справа допустимы пробельные символы). Препроцессор
объединяет такие лексемы в одну. Например, макроопределение #define VAR(i, j) i ## j при
макровызове VAR(x, 6) образует идентификатор x6.
Символ #, помещаемый перед аргументом макроопределения, указывает на необходимость
преобразования его в символьную строку. При макровызове конструкция #<формальный
параметр> заменяется на "<фактический параметр>".
Замены в тексте можно отменить директивой #undef, которая имеет следующий синтаксис:
#undef <идентификатор>
Директива #undef отменяет действие текущего определения #define для идентификатора.
Чтобы отменить макроопределение, достаточно задать его идентификатор. Задание
списка параметров не требуется. Не является ошибкой применение директивы #undef к
идентификатору, который ранее не был определён или действие которого уже отменено.
Принятая в С/С++ форма макросов является серьезным недостатком языка. Теперь эту
форму можно считать устаревшей благодаря наличию более подходящих средств языка,
таких как шаблоны, пространства имён, встраиваемые функции и константы. Точно также,
широкое использование приведений типа в любом языке сигнализирует о плохом
проектировании. Как макросы, так и приведения являются частыми источниками ошибок.
Тот факт, что без них можно обойтись, делает программирование на С++ гораздо более
безопасным и элегантным.
2.3.3. Условная компиляция
Условная компиляция обеспечивается в языке С++ набором команд, которые, по существу,
управляют не компиляцией, а препроцессорной обработкой. Эти директивы позволяют
исключить из процесса компиляции какиелибо части исходного файла посредством
проверки условий.
#if <константное выражение> [<текст>] [#elif <константное выражение>
[<текст>]] ... [#else [<текст>]] #endif
Каждой директиве #if в том же исходном файле должна соответствовать завершающая её
директива #endif. Между директивами #if и #endif допускается произвольное количество
директив #elif и не более одной директивы #else. Если директива #else присутствует, то
между ней и директивой #endif на данном уровне вложенности не должно быть других
директив #elif.
Препроцессор выбирает участок текста для обработки на основе вычисления
константного выражения, следующего за каждой директивой #if и #elif. Выбирается
текст, следующий за константным выражением со значением «истина». Если ни одно ограниченное константное выражение не истинно, то препроцессор выбирает текст,
следующий за директивой #else. Если же директива #else отсутствует, то никакой текст не
выбирается.
Константное выражение может содержать препроцессорную операцию
defined(<идентификатор>). Эта операция возвращает истинное значение, если заданный
идентификатор в данный момент определён, в противном случае выражение ложно.
#if (sizeof(void *) == 2) #define SDATA #else #define LDATA #endif #if defined(CREDIT)
credit(); #elif defined(DEBIT) debit(); #else printerror(); #endif
3. Пример
3.1. Программа поиска корня уравнения f(x) = 0 на отрезке [a; b] с заданной
точностью
        методом деления отрезка пополам
Первый вариант – обычный способ
#include  #include  void main()
{ double a, b, e, x, c, fa, fc; int n; printf("Введите
границы отрезка и точность: "); scanf("%lf%lf%lf",
&a, &b, &e); for (n = 0; fabs(a  b) > e; n++) { c = (a
+ b) / 2; fa = f(a); fc = f(c); if (fa * fc < 0) b = c; else
a = c; } x = (a + b) / 2; printf("Корень уравнения =
%lf\nЧисло итераций = %d\n", x, n); }
// Включаем заголовочные файлы, //
содержащие прототипы функций
ввода/вывода // и математических
функций (для fabs) // Объявления
переменных // Приглашение для
пользователя // Ввод исходных данных //
В заголовок цикла for включаем
инициализацию переменной n, // её
увеличение на 1, т.к. оно безусловно
выполняется // на каждом шаге цикла, и
проверку условия цикла // Т.к. в теле
цикла должно быть более одного
оператора, // а по синтаксису возможен
только один, // операторы, составляющие
тело цикла, // объединяются в один с
помощью операторных скобок {...}
Второй вариант – как на Паскале
#include  #include  void main() { double a, b, e, x, c, fa, fc; int n;
printf("Введите границы отрезка и точность: "); scanf("%lf%lf%lf", &a, &b, &e); n = 0; while
(fabs(a  b) > e) { c = (a + b) / 2; fa = f(a); fc = f(c); if (fa * fc < 0) b = c; else a = c; n++; } x = (a
+ b) / 2; printf("Корень уравнения = %lf\nЧисло итераций = %d\n", x, n); }
Третий вариант – весь алгоритм помещен в заголовок цикла for
#include  #include  void main() { double a,
b, e, x, c, fa, fc; int n; printf("Введите границы отрезка и
точность: "); scanf("%lf%lf%lf", &a, &b, &e); for (n = 0;
fabs(a  b) > e; c = (a + b) / 2, fa = f(a), fc = f(c), fa * fc < 0 ? b
= c : a = c, n++) ; x = (a + b) / 2; printf("Корень уравнения =
%lf\nЧисло итераций = %d\n", x, n); }
// Для объединения нескольких
операторов // в выражении
приращения цикла

используется // операция
последовательного вычисления
 for
3.2. Функция с переменным числом параметров, аналогичная функции printf
#include  #include
void print(char *format, ...); void
main() { int a = 45, b = 87; double f =
// Переменная для работы со списком аргументов //
Инициализация указателя на список аргументов //
Выбираем очередной параметр // Выбираем очередной 2.75; print("dfd", a, f, b); } void
print(char * format, ...) { va_list list;
int n, i; double f; va_start(list, format);
for (i = 0; format[i]; i++)
switch(format[i]) { case 'd': n =
va_arg(list, int); printf("%d\n", n);
break; case 'f': f = va_arg(list, double);
printf("%lf\n", f); break; }
va_end(list); }
параметр // Сброс указателя на список аргументов в
NULL

file_name: тема 2 вопрос 32.docx

description:
тема 2 вопрос 32
структура программы в c++ примеры
Структура программы на языке С++.
Выглядит схема примерно так:
Подключаемые внешние файлы (*.h, *.cpp)
Обьявление глобальных переменных и функций
int main(список аргументов)
{
последовательность операторов
}
тип_возвращаемого_значения имя_функции (список входных параметров)
{
последовательность операторов
}
Этой схеме можно привести простейший пример на C++:
#include <stdio.h>
int main(int argc, char* argv[])
{
// тело функции
return 0;
}
int& min(int& a, int& b)
{
if (a>b)
return a;
return b;
}
Программа на языке С++ может состоять из одной и более функций,
но функция ... main( ... ) должна быть только одна.
Именно с этой функции начинается выполнение программы, поэтому, при отсутствии ( или в наличии
более чем один экземпляр ) такой функции
компилятор выдаст соответствующее сообщение об ошибке.
Еще такое замечание, в С и С++ любая последовательность операторов заканчивается ';'  символом
точка с запятой,
поэтому будьте внимательны, когда набираете программу, если забудете поставить  компилятор
выдаст сообщение об ошибке: в строке такой то нехватает символа ';'.
Комментарии в программе пишутся после " // " или между " /* ... */ ". В первом случае их размер не
должен превышать размера строки, во втором размер неограничен.
2. Структура программы
Программа на языке С++ состоит из директив препроцессора, указаний компилятору, объявлений
переменных и/или констант, объявлений и определений функций.
2.1. Объявление переменной
Объявление переменной задаёт имя и атрибуты переменной. Атрибутами переменной могут быть тип,
количество элементов (для массивов), спецификация класса памяти, а также инициализатор.
Инициализатор – это константа соответствующего типа, задающая значение, которое присваивается
переменной при создании.
Объявление переменной имеет следующий синтаксис: [<спецификация класса памяти>]
<тип> <имя> [= <инициализатор>] [,<имя> [= <инициализатор>] ...];
Примеры объявления переменных
int x;
double y = exp(1);
// Объявление переменной целого типа без
инициализатора
// Переменная вещественного типа инициализируется
числом e. // exp(x) – функция, вычисляющая ex.

description:
ограниченное константное выражение не истинно, то препроцессор выбирает текст,
следующий за директивой #else. Если же директива #else отсутствует, то никакой текст не
выбирается.
Константное выражение может содержать препроцессорную операцию
defined(<идентификатор>). Эта операция возвращает истинное значение, если заданный
идентификатор в данный момент определён, в противном случае выражение ложно.
#if (sizeof(void *) == 2) #define SDATA #else #define LDATA #endif #if defined(CREDIT)
credit(); #elif defined(DEBIT) debit(); #else printerror(); #endif
3. Пример
3.1. Программа поиска корня уравнения f(x) = 0 на отрезке [a; b] с заданной
точностью
        методом деления отрезка пополам
Первый вариант – обычный способ
#include <cstdio> #include <math.h> void main()
{ double a, b, e, x, c, fa, fc; int n; printf("Введите
границы отрезка и точность: "); scanf("%lf%lf%lf",
&a, &b, &e); for (n = 0; fabs(a  b) > e; n++) { c = (a
+ b) / 2; fa = f(a); fc = f(c); if (fa * fc < 0) b = c; else
a = c; } x = (a + b) / 2; printf("Корень уравнения =
%lf\nЧисло итераций = %d\n", x, n); }
// Включаем заголовочные файлы, //
содержащие прототипы функций
ввода/вывода // и математических
функций (для fabs) // Объявления
переменных // Приглашение для
пользователя // Ввод исходных данных //
В заголовок цикла for включаем
инициализацию переменной n, // её
увеличение на 1, т.к. оно безусловно
выполняется // на каждом шаге цикла, и
проверку условия цикла // Т.к. в теле
цикла должно быть более одного
оператора, // а по синтаксису возможен
только один, // операторы, составляющие
тело цикла, // объединяются в один с
помощью операторных скобок {...}
Второй вариант – как на Паскале
#include <cstdio> #include <math.h> void main() { double a, b, e, x, c, fa, fc; int n;
printf("Введите границы отрезка и точность: "); scanf("%lf%lf%lf", &a, &b, &e); n = 0; while
(fabs(a  b) > e) { c = (a + b) / 2; fa = f(a); fc = f(c); if (fa * fc < 0) b = c; else a = c; n++; } x = (a
+ b) / 2; printf("Корень уравнения = %lf\nЧисло итераций = %d\n", x, n); }
Третий вариант – весь алгоритм помещен в заголовок цикла for
#include <cstdio> #include <math.h> void main() { double a,
b, e, x, c, fa, fc; int n; printf("Введите границы отрезка и
точность: "); scanf("%lf%lf%lf", &a, &b, &e); for (n = 0;
fabs(a  b) > e; c = (a + b) / 2, fa = f(a), fc = f(c), fa * fc < 0 ? b
= c : a = c, n++) ; x = (a + b) / 2; printf("Корень уравнения =
%lf\nЧисло итераций = %d\n", x, n); }
// Для объединения нескольких
операторов // в выражении
приращения цикла

используется // операция
последовательного вычисления
 for
3.2. Функция с переменным числом параметров, аналогичная функции printf
#include <cstdio> #include <stdarg.h>
void print(char *format, ...); void
main() { int a = 45, b = 87; double f =
// Переменная для работы со списком аргументов //
Инициализация указателя на список аргументов //
Выбираем очередной параметр // Выбираем очередной

title: Лекция "Структура программы в c++ примерыы"


extracted_text:
конструкторы и деструкторы в с++ примеры использования конструкторов  и деструкторов в с+
тема 2 вопрос 34
Перед использованием объекта может потребоваться инициализировать некоторые его данные. Для
примера рассмотрим класс queue, определенный выше в этой главе. Перед тем как использовать queue,
необходимо присвоить переменным rloc и sloc значения 0, используя функцию init(). Поскольку
требование инициализации является чрезвычайно распространенным, то С++ позволяет производить
инициализацию объектов во время их создания. Такая автоматическая инициализация выполняется с
помощью функции, которая называется конструктором.
Функцияконструктор, являющаяся членом класса и имеющая имя, совпадающее с именем класса,
представляет собой специальный тип функции. В качестве примера ниже показано, как выглядит класс
queue, преобразованный таким образом, чтобы использовать для инициализации конструктор:
/ / создание класса очередь
class queue {
int q[100];
int sloc, rloc;
public:
queue (); // конструктор
void qput(int i);
int qget ();};
Обратим внимание, что конструктор queue() не имеет типа возвращаемого значения. В С++ функции
конструкторы не могут возвращать значений.
Код, реализующий функцию queue(), выглядит следующим образом:
// конструктор
queue ::queue ()
{sloc = rloc = 0;
cout << "Queue initialized. \n";
}
Обратим внимание, что выводимое сообщение «queue initialized» служит для иллюстрации работы
конструктора. В обычной практике большинство конструкторов не занимаются выводом или вводом
данных. Они служат для инициализации.
Конструктор объекта вызывается автоматически при создании объекта. Это означает, что он вызывается
тогда, когда происходит объявление объекта. В этом заключается важнейшее различие между
объявлениями в языке С и в С++. В С объявления переменных, попросту говоря, являются пассивными и
в большинстве случаев выполняются во время компиляции. Иными словами, в языке С объявления
переменных не являются исполнимыми инструкциями. В отличие от этого в С++ объявления переменных
служат активными инструкциями, исполняемыми по существу во время работы программы. Одна из
причин этого заключается в том, что объявление объекта может требовать вызова конструктора, то есть
вызывать выполнение функции. Хотя это различие может показаться едва уловимым и носить больше
академический характер, как будет видно далее, оно может оказывать существенное влияние на
инициализацию переменных.
При инициализации глобальных или статических объектов конструктор вызывается только один раз. Для
локальных объектов конструктор вызывается всякий раз, когда встречается объявление объекта.
Дополнением конструктора является деструктор. Во многих случаях перед уничтожением объекта
необходимо выполнить определенные действия. Локальные объекты создаются при входе в соот
ветствующий блок программы и разрушаются при выходе из него. Глобальные объекты уничтожаются
при завершении работы программы. Имеется много причин тому, чтобы существовал деструктор.
Например, может потребоваться освободить память, которая была ранее зарезервирована. В С++ за
дезактивацию отвечает деструктор. Он имеет то же самое имя, что и конструктор, только к нему
добавлен значок ~. Ниже представлен вариант класса queue, использующий конструктор и деструктор.
(Следует иметь в виду, что класс queue не нуждается в деструкторе, поэтому ниже он приведен только
для иллюстрации.)
// создание класса очередь
class queue { int q[100];int sloc, rloc;
public:queue(); // конструктор
~queue(); // деструктор
void gput(int i);
int qget();
};// конструктор
queue::queue()
{sloc = rloc = 0;
cout << "Queue initialized.\n";
}
// деструктор
queue ::~queue (){
cout << "Queue destroyed.\n";}
Для того чтобы продемонстрировать работу конструктора и деструктора, ниже представлена новая
версия программы:
#include
// создание класса очередь
class queue {
int q[100];
int sloc, rloc;
public :
queue (); // конструктор
~queue(); // деструктор
void gput(int i);
int qget();
};/ / конструктор
queue::queue ()
{sloc = rloc = 0;
cout << "Queue initialized.\n";
}// деструктор
queue::~queue ()
{cout << "Queue destroyed.\n";
}void queue::qput(int i)
{
if (sloc == 99) {
cout << "Queue is full.\n";
return;
}sloc++;
q[sloc] = i;
}int queue::qget()
{
if (rloc == sloc) {
cout << "Queue underflow.\n";
return 0;
}rloc++;
return q[rloc];
}int main()
{
queue a, b; // создание двух объектов типа queue
a.qput(10);
b.qput(19) ;
a.qput(20);
b.qput(1);
cout << a.qget ()<< " "; cout << a.qget ()<< " ";
cout << b.qget()<<" ";
cout << b.qget()<< "\n";
return 0;}
Эта программа выводит на экран следующий текст:
Queue initialized.
Queue initialized.
10 20 19 1
Queue destroyed.
Queue destroyed.
ачнем с того, что когда мы создаем элементы (переменные) класса, мы не можем присвоить
им   значения   в   самом   определении   класса.   Компилятор   выдаст   ошибку.   Поэтому   нам
необходимо создавать отдельный метод (так называемую setфункцию) класса, с помощью
которого и будет происходить инициализация элементов. При этом, если необходимо создать,
к примеру, 20 объектов класса, то чтобы инициализировать элементы потребуется 20 раз
вызвать setфункции.
Тут нам как раз сможет помочь конструктор класса. Кстати, конструктор (от слова construct
— создавать) – это специальный метод  класса, который  предназначен  для инициализации
элементов класса некоторыми начальными значениями.
В отличии  от конструктора,  деструктор  (от слова  destruct  —  разрушать)  — специальный
метод   класса,   который   служит   для   уничтожения   элементов   класса.   Чаще   всего   его
используют   тогда,   когда   в   конструкторе,при   создании   объекта   класса,   динамически   был
выделен участок памяти и необходимо эту память очистить, если эти значения уже не нужны
для дальнейшей работы программы.
Важно запомнить:
конструктор и деструктор, мы всегда объявляем в разделе public;
при объявлении конструктора, тип данных возвращаемого значения не указывается, в
том числе — void!!!;
у   деструктора   так   же   нет   типа   данных   для   возвращаемого   значения,   к   тому   же
деструктору нельзя передавать никаких параметров;
имя класса и конструктора должно быть идентично;
имя деструктора идентично имени конструктора, но с приставкой ~ ;
В классе допустимо создавать несколько конструкторов, если это необходимо. Имена,
согласно пункту 2 нашего списка, будут одинаковыми. Компилятор будет их различать по передаваемым
параметрам (как при перегрузке функций). Если мы не передаем в конструктор параметры, он считается
конструктором по умолчанию;
Обратите внимание на то, что в классе может быть объявлен только один деструктор;
Сразу хочу привести пример, который доступно покажет, как работает конструктор:
# include
using namespace std;

class AB //класс
{
    private:
    int a;
    int b;
    public:
    AB()    //это конструктор:  1) у конструктора нет типа возвращаемого значения! в том числе
void!!!
    //   2) имя должно быть таким как и у класса (в нашем случае AB)
    {
        a = 0;//присвоим начальные значения переменным
1.
2.
3.
4.
5.
6.
7. b = 0;
        cout << "Работа конструктора при создании нового объекта: " << endl;//и здесь же их
отобразим на экран
        cout << "a = " << a << endl;
        cout << "b = " << b << endl << endl;
    }

    void setAB() // с помощью этого метода изменим начальные значения заданные
конструктором
    {
        cout << "Введите целое число а: ";
        cin >> a;
        cout << "Введите целое число b: ";
        cin >> b;
    }

    void getAB() //выведем на экран измененные значения
    {
        cout << "a = " << a << endl;
        cout << "b = " << b << endl << endl;
int main()
    setlocale(LC_ALL, "rus");

    AB obj1;     //конструктор сработает на данном этапе (во время создания объекта класса)

    obj1.setAB();   //присвоим новые значения переменным
    obj1.getAB();   //и выведем их на экран

    AB obj2;     //конструктор сработает на данном этапе (во время создания 2го объекта
класса)
Результат работы программы:
CppStudio.com
Работа конструктора при создании нового объекта:
a = 0b = 0
Введите целое число а: 34
Введите целое число b: 67
a = 34b = 67
Работа конструктора при создании нового объекта:
a = 0
b = 0
Как видно из результата работы программы, конструктор срабатывает сразу, при создании объектов
класса, поэтому, явно вызывать конструктор не нужно, он сам «приходит» :)
Хочется еще добавить, что, как и обычным функциям, мы можем передавать конструктору параметры.
Через   параметры,   конструктору   можно   передавать   любые   данные,   которые   будут   необходимы   при
инициализации объектов класса.
Рассмотрим еще один пример, это все та же программа, только в код внесены некоторые изменения. Тут
же покажем принцип работы деструктора: Смотрим результат работы программы:
CppStudio.com
Тут сработал конструктор, который принимает параметры:
a = 100
b = 100
Введите целое число а: 333
Введите целое число b: 333
a = 333
b = 333
Тут сработал конструктор, который принимает параметры:
a = 200
b = 200
Тут сработал деструктор
Тут сработал деструктор
Деструктор срабатывает в тот момент, когда завершается работа программы и уничтожаются все данные.
Мы его не вызывали – он сработал сам. Как видно, он сработал 2 раза, так как и конструктор. Уже от
себя добавлю, что, в первую очередь, он удалил второй созданный объект (где a = 200, b = 200), а затем
первый (где a = 100, b = 100). «Последним пришёл — первым вышел».
Конструкторы и деструкторы в С++
В больших программах в некоторых частях программы обычно требуется инициализация. Необходимость
в инициализации еще чаще требуется при работе с объектами. Действительно, фактически, для каждого
создаваемого вами объекта требуется какогото вида инициализация. Для решения этой проблемы в C++
имеется функцияконструктор (constructor function), включаемая в описание класса. Конструктор класса
вызывается всякий раз при создании объекта этого класса. Таким образом, любая необходимая объекту
инициализация при наличии конструктора выполняется автоматически.
Конструктор имеет то же имя, что и класс, частью которого он является, и не имеет возвращаемого
значения. Ниже представлен небольшой класс с конструктором:
#include
using namespace std;
class myclass {
int a;
public:
myclass (); // конструктор
void show() ;
myclass :: myclass ( )
{
cout ≪ "В конструкторе\n";
a=10;
)
void myclass :: show ()
{
cout ≪ a;
}
int main ( )
{
myclass ob;
ob. show();
return 0;
}
В этом простом примере значение а инициализируется конструктором myclass(). Конструктор
вызывается тогда, когда создается объект ob. Объект, в свою очередь, создается при выполнении
инструкции объявления объекта.
Функцией, обратной конструктору, является деструктор (destructor). Эта функция вызывается при
удалении объекта. Обычно при работе с объектом в момент его удаления должны выполняться
некоторые действия. Например, при создании объекта для него выделяется память, которую необходимо
освободить при его удалении. Имя деструктора совпадает с именем класса, но с символом ~ (тильда) в
начале.
В следующем примере показана необходимость не только конструктора, но и деструктора.
Замечание. В программе используется стандартная библиотечная функция clock(), которая возвращает
число временных циклов с момента запуска программы. Если разделить это число на
CLOCKS_PER_SEC, можно получить значение в секундах.
Конструктору можно передавать аргументы. Для этого просто добавьте необходимые параметры в
объявление и определение конструктора. Затем при объявлении объекта задайте параметры в качестве
аргументов.
Пример. Здесь 4 передается в х, а 7 передается в у.
#include
using namespace std;
class myclass {
myclass(int x, int y); //
конструктор
void show();
myclass::myclass(int x, int y)
cout << "В конструкторе\n";
void myclass::show()
cout << a << ' ' << b << "\n";
int main()
myclass ob(4, 7);
ob.show();
return 0;
 Пример. Здесь представлена следующая версия класса stack, в котором конструктор с параметром
используется для присвоения стеку "имени". Это односимвольное имя необходимо для идентификации
стека в случае возникновения ошибки.
#include
using namespace std;
#define SIZE 10
// Объявление класса stack для символов
class stack {
char stck[SIZE]; // содержит стек
int tos; // индекс вершины стека
char who; // идентифицирует стек
stack(char c); // конструктор
void push(char ch); // помещает в стек символ
char pop(); // выталкивает из стека символ
// Инициализация стека
stack::stack(char c)
who = c;
cout << "Работа конструктора стека " << who << "\n";
// Помещение символа в стек
void stack::push(char ch)
if (tos==SIZE) {
cout << "Стек " << who << " полон \n";
stck[tos]=ch;
// Выталкивание символа из стека
char stack::pop()
if (tos==0) {
cout << "Стек " << who << " пуст ";
return 0; // возврат нуля при пустом стеке
return stck[tos];
int main()
// образование двух, автоматически инициализируемых,
// стеков stack s1('A'), s2('B'); s1.push('a');
s2.push('x');
s1.push('b');
s2.push('y');
s1.push('c');
s2.push('z');
// Это вызовет сообщения об ошибках
for(i=0; i<5; i++) cout << "символ из стека s1: " << s1.pop() << "\n";
for(i=0; i<5; i++) cout << "символ из стека s2: " << s2.pop() << "\n";
return 0;

Пример. Вариант класса strtype, в котором используется конструктор с параметром:
Пример. Объекты могут создаваться по мере необходимости, точно в соответствии с возникающей в
момент их создания ситуацией. Конструктору объекта можно передать не только константы, но и любые
допустимые выражения с переменными. Например, в следующей программе для создания объекта
используется пользовательский ввод:
#include
using namespace std;
 class myclass {
 int i, j;
public:
 myclass(int a, int b);
 void show();
};
 myclass::myclass(int a, int b)
{
 i = a;
 j = b;
} void myclass::show()
{ cout << i << ' ' << j << "\n";
} int main()
{ int x, y;
  cout << "Введите два целых: ";
 cin >> x >> y;
  // использование переменных для создания ob
 myclass ob(x, y);
  ob.show();

 return 0;
}

file_name: тема 2 вопрос 34.docx

description:
int q[100];int sloc, rloc;
public:queue(); // конструктор
~queue(); // деструктор
void gput(int i);
int qget();
};// конструктор
queue::queue()
{sloc = rloc = 0;
cout << "Queue initialized.\n";
}
// деструктор
queue ::~queue (){
cout << "Queue destroyed.\n";}
Для того чтобы продемонстрировать работу конструктора и деструктора, ниже представлена новая
версия программы:
#include <iostream.h>
// создание класса очередь
class queue {
int q[100];
int sloc, rloc;
public :
queue (); // конструктор
~queue(); // деструктор
void gput(int i);
int qget();
};/ / конструктор
queue::queue ()
{sloc = rloc = 0;
cout << "Queue initialized.\n";
}// деструктор
queue::~queue ()
{cout << "Queue destroyed.\n";
}void queue::qput(int i)
{
if (sloc == 99) {
cout << "Queue is full.\n";
return;
}sloc++;
q[sloc] = i;
}int queue::qget()
{
if (rloc == sloc) {
cout << "Queue underflow.\n";
return 0;
}rloc++;
return q[rloc];
}int main()
{
queue a, b; // создание двух объектов типа queue
a.qput(10);
b.qput(19) ;
a.qput(20);
b.qput(1);
cout << a.qget ()<< " ";

description:
cout << a.qget ()<< " ";
cout << b.qget()<<" ";
cout << b.qget()<< "\n";
return 0;}
Эта программа выводит на экран следующий текст:
Queue initialized.
Queue initialized.
10 20 19 1
Queue destroyed.
Queue destroyed.
ачнем с того, что когда мы создаем элементы (переменные) класса, мы не можем присвоить
им   значения   в   самом   определении   класса.   Компилятор   выдаст   ошибку.   Поэтому   нам
необходимо создавать отдельный метод (так называемую setфункцию) класса, с помощью
которого и будет происходить инициализация элементов. При этом, если необходимо создать,
к примеру, 20 объектов класса, то чтобы инициализировать элементы потребуется 20 раз
вызвать setфункции.
Тут нам как раз сможет помочь конструктор класса. Кстати, конструктор (от слова construct
— создавать) – это специальный метод  класса, который  предназначен  для инициализации
элементов класса некоторыми начальными значениями.
В отличии  от конструктора,  деструктор  (от слова  destruct  —  разрушать)  — специальный
метод   класса,   который   служит   для   уничтожения   элементов   класса.   Чаще   всего   его
используют   тогда,   когда   в   конструкторе,при   создании   объекта   класса,   динамически   был
выделен участок памяти и необходимо эту память очистить, если эти значения уже не нужны
для дальнейшей работы программы.
Важно запомнить:
конструктор и деструктор, мы всегда объявляем в разделе public;
при объявлении конструктора, тип данных возвращаемого значения не указывается, в
том числе — void!!!;
у   деструктора   так   же   нет   типа   данных   для   возвращаемого   значения,   к   тому   же
деструктору нельзя передавать никаких параметров;
имя класса и конструктора должно быть идентично;
имя деструктора идентично имени конструктора, но с приставкой ~ ;
В классе допустимо создавать несколько конструкторов, если это необходимо. Имена,
согласно пункту 2 нашего списка, будут одинаковыми. Компилятор будет их различать по передаваемым
параметрам (как при перегрузке функций). Если мы не передаем в конструктор параметры, он считается
конструктором по умолчанию;
Обратите внимание на то, что в классе может быть объявлен только один деструктор;
Сразу хочу привести пример, который доступно покажет, как работает конструктор:
# include <iostream>
using namespace std;

class AB //класс
{
    private:
    int a;
    int b;
    public:
    AB()    //это конструктор:  1) у конструктора нет типа возвращаемого значения! в том числе
void!!!
    //   2) имя должно быть таким как и у класса (в нашем случае AB)
    {
        a = 0;//присвоим начальные значения переменным
1.
2.
3.
4.
5.
6.
7.

description:
Смотрим результат работы программы:
CppStudio.com
Тут сработал конструктор, который принимает параметры:
a = 100
b = 100
Введите целое число а: 333
Введите целое число b: 333
a = 333
b = 333
Тут сработал конструктор, который принимает параметры:
a = 200
b = 200
Тут сработал деструктор
Тут сработал деструктор
Деструктор срабатывает в тот момент, когда завершается работа программы и уничтожаются все данные.
Мы его не вызывали – он сработал сам. Как видно, он сработал 2 раза, так как и конструктор. Уже от
себя добавлю, что, в первую очередь, он удалил второй созданный объект (где a = 200, b = 200), а затем
первый (где a = 100, b = 100). «Последним пришёл — первым вышел».
Конструкторы и деструкторы в С++
В больших программах в некоторых частях программы обычно требуется инициализация. Необходимость
в инициализации еще чаще требуется при работе с объектами. Действительно, фактически, для каждого
создаваемого вами объекта требуется какогото вида инициализация. Для решения этой проблемы в C++
имеется функцияконструктор (constructor function), включаемая в описание класса. Конструктор класса
вызывается всякий раз при создании объекта этого класса. Таким образом, любая необходимая объекту
инициализация при наличии конструктора выполняется автоматически.
Конструктор имеет то же имя, что и класс, частью которого он является, и не имеет возвращаемого
значения. Ниже представлен небольшой класс с конструктором:
#include <iostream>
using namespace std;
class myclass {
int a;
public:
myclass (); // конструктор
void show() ;
myclass :: myclass ( )
{
cout ≪ "В конструкторе\n";
a=10;
)
void myclass :: show ()
{
cout ≪ a;
}
int main ( )
{
myclass ob;
ob. show();
return 0;
}

description:
</iostream>
В этом простом примере значение а инициализируется конструктором myclass(). Конструктор
вызывается тогда, когда создается объект ob. Объект, в свою очередь, создается при выполнении
инструкции объявления объекта.
Функцией, обратной конструктору, является деструктор (destructor). Эта функция вызывается при
удалении объекта. Обычно при работе с объектом в момент его удаления должны выполняться
некоторые действия. Например, при создании объекта для него выделяется память, которую необходимо
освободить при его удалении. Имя деструктора совпадает с именем класса, но с символом ~ (тильда) в
начале.
В следующем примере показана необходимость не только конструктора, но и деструктора.
Замечание. В программе используется стандартная библиотечная функция clock(), которая возвращает
число временных циклов с момента запуска программы. Если разделить это число на
CLOCKS_PER_SEC, можно получить значение в секундах.
Конструктору можно передавать аргументы. Для этого просто добавьте необходимые параметры в
объявление и определение конструктора. Затем при объявлении объекта задайте параметры в качестве
аргументов.
Пример. Здесь 4 передается в х, а 7 передается в у.
#include <iostream>
using namespace std;
class myclass {
myclass(int x, int y); //
конструктор
void show();
myclass::myclass(int x, int y)
cout << "В конструкторе\n";
void myclass::show()
cout << a << ' ' << b << "\n";
int main()
myclass ob(4, 7);
ob.show();
return 0;
</iostream>

description:
Пример. Здесь представлена следующая версия класса stack, в котором конструктор с параметром
используется для присвоения стеку "имени". Это односимвольное имя необходимо для идентификации
стека в случае возникновения ошибки.
#include <iostream>
using namespace std;
#define SIZE 10
// Объявление класса stack для символов
class stack {
char stck[SIZE]; // содержит стек
int tos; // индекс вершины стека
char who; // идентифицирует стек
stack(char c); // конструктор
void push(char ch); // помещает в стек символ
char pop(); // выталкивает из стека символ
// Инициализация стека
stack::stack(char c)
who = c;
cout << "Работа конструктора стека " << who << "\n";
// Помещение символа в стек
void stack::push(char ch)
if (tos==SIZE) {
cout << "Стек " << who << " полон \n";
stck[tos]=ch;
// Выталкивание символа из стека
char stack::pop()
if (tos==0) {
cout << "Стек " << who << " пуст ";
return 0; // возврат нуля при пустом стеке
return stck[tos];
int main()
// образование двух, автоматически инициализируемых,
// стеков stack s1('A'), s2('B');

description:
s1.push('a');
s2.push('x');
s1.push('b');
s2.push('y');
s1.push('c');
s2.push('z');
// Это вызовет сообщения об ошибках
for(i=0; i<5; i++) cout << "символ из стека s1: " << s1.pop() << "\n";
for(i=0; i<5; i++) cout << "символ из стека s2: " << s2.pop() << "\n";
return 0;
</iostream>
Пример. Вариант класса strtype, в котором используется конструктор с параметром:
Пример. Объекты могут создаваться по мере необходимости, точно в соответствии с возникающей в
момент их создания ситуацией. Конструктору объекта можно передать не только константы, но и любые
допустимые выражения с переменными. Например, в следующей программе для создания объекта
используется пользовательский ввод:
#include <iostream>
using namespace std;
 class myclass {
 int i, j;
public:
 myclass(int a, int b);
 void show();
};
 myclass::myclass(int a, int b)
{
 i = a;
 j = b;
} void myclass::show()
{ cout << i << ' ' << j << "\n";
} int main()
{ int x, y;
  cout << "Введите два целых: ";
 cin >> x >> y;
  // использование переменных для создания ob
 myclass ob(x, y);
  ob.show();

 return 0;
}
</iostream>

intro:
Перед использованием объекта может потребоваться инициализировать некоторые его данные. Для примера рассмотрим класс queue, определенный выше в этой главе. Перед тем как использо¬вать queue, необходимо присвоить переменным rloc и sloc значения 0, используя функцию init(). Поскольку требование инициализации является чрезвычайно распространенным, то С++ позво¬ляет производить инициализацию объектов во время их создания. Такая автоматическая иници¬ализация выполняется с помощью функции, которая называется конструктором.
Функция-конструктор, являющаяся членом класса и имеющая имя, совпадающее с именем класса, представляет собой специальный тип функции. В качестве примера ниже показано, как выглядит класс queue, преобразованный таким образом, чтобы использовать для инициализации конструктор:

информатика

group: Дисциплины

title: Лекция "Конструкторы и деструкторы в с++ "


extracted_text:
тема 2 вопрос 35
потоки ввода вывода в с++ классы потоков операции помещения в поток и извлечения из потока
примеры
Главным преимуществом системы вводавывода C++ является то, что она может перегружаться для
создаваемых классов.
Поток вводавывода – это логическое устройство, предназначенное для приема и выдачи информации
пользователю. Поток связан с физическим устройством с помощью системы вводавывода C++. Поток
обеспечивает пользователю единый интерфейс при работе с системой вводавывода. Это означает, что,
например, для вывода информации на экран монитора и для записи ее в файл используется одна и та же
функция.
Когда программа на C++ начинает выполняться, автоматически создаются восемь предопределенных
стандартных потоков. Эти стандартные потоки связаны со стандартными файлами языка C следующим
образом:
поток для "узких" символов cin cout cerr clog
поток для "широких" символов wcin wcout wclog
стандартный файл языка C stdin stdout stderr stderr
Объект cinуправляет вводом из буфера потока, связанного с объектом stdin, объявленным в . По
умолчанию эти два потока синхронизированы.
Объект cout управляет буфером потока, связанным с объектом stdout, объявленным в . По
умолчанию эти два потока также синхронизированы.
Поток clog – это просто буферизованная версия потока cerr. В буферизованной версии потока запись на
реальное внешнее устройство делается, только когда буфер полон. Поэтому clog является более
эффективным для перенаправления вывода в файл, в то время как cerr используется главным образом
для вывода на экран терминала.
Система вводавывода содержит две иерархии классов: первая предназначена для работы с ASCII
символами, имеющими длину 8 бит; вторая предназначена для работы с UNICODEсимволами,
имеющими длину 16 бит.
Символы первого набора называются "узкими", а второго – "широкими".
В основе иерархии потоковых классов лежит класс basic_ios.
Класс basic_ios является базовым для нескольких производных классов, среди которых классы
basic_istream, basic_ostream и basic_iostream. Он содержит наиболее общие функции, необходимые для
всех потоков, и обслуживает информацию о состоянии, которая отражает целостность потока и буфер
потока. Классы, производные от basiс_ios, специализируют операции вводавывода. В свою очередь,
basic_ios использует класс ios_base, который также является базовым классом для всех потоковых
классов. Он не зависит от типа символов и инкапсулирует информацию, необходимую для всех потоков.
Этот класс определяет несколько типов данных, используемых всеми потоковыми классами, такие как
флаги форматирования, биты состояния, режимы открытия файлов и т.д.
С целью обеспечения совместимости с традиционной версией библиотеки вводавывода C++ введены
синонимы для имен потоковых классов:
Шаблон класса
Синоним
Шаблон класса
Синоним
basic_ios basic_ifstream
ifstream
basic_istream
basic_ofstream
ofstream
basic_оstream
оstream
basic_fstream
basic_streambuf
iostream
basic_iostream
streambuf Имена синонимов в точности соответствуют именам потоковых классов в традиционной версии
библиотеки вводавывода C++. Далее при изложении потокового вводавывода и мы будем пользоваться
этими именами, поскольку как раз эти имена следует указывать в программах.
Библиотека вводавывода содержит два параллельных семейства классов: одно – производное от
streambuf и второе – производное от ios. Оба эти класса являются низкоуровневыми, выполняющими
различный вид задач. Все потоковые классы имеют, по крайней мере, один из этих классов в качестве
базового. Доступ из iosпроизводных классов к streambufпроизводным осуществляется через указатель.
Класс streambuf обеспечивает интерфейс с памятью и физическими устройствами. Функциичлены
семейства классов streambuf используются iosпроизводными классами.
Назначение классов потокового вводавывода следующее:
istreamпотоковый класс общего назначения для ввода, являющийся базовым классом для других
потоков ввода;
ifstreamпотоковый класс для ввода из файла;
istream_withassignпотоковый класс ввода для cin;
istrstrearmпотоковый класс для ввода строк;
оstreamпотоковый класс общего назначения для вывода, являющийся базовым классом для других
потоков вывода;
ofstreamпотоковый класс для вывода в файл;
ostream_withassignпотоковый класс ввода для cout, cerr, clog;
ostrstreamпотоковый класс для вывода строк;
iostreamпотоковый класс общего назначения для вводавывода, являющийся базовым классом для
других потоков вводавывода;
fstreamпотоковый класс для вводавывода в файл;
strstreamпотоковый класс для вводавывода строк;
stdiostreamкласс для вводавывода в стандартные файлы вводавывода;
streambufабстрактный базовый класс буфера потока;
filebufкласс буфера потока для дисковых файлов;
strstreambufкласс буфера потока для строк;
stdiobufкласс буфера потока для стандартных файлов вводавывода.
Назначение почти всех классов следует из их названия. Классы группы _withassign являются
производными соответствующих потоковых классов без этого окончания. Они перегружают оператор
присваивания, что позволяет изменять указатель на используемый классом буфер. Если подключен
заголовочный файл , программы, написанные на языке C++, начинают выполняться с
четырьмя открытыми предопределенными потоками, объявленными как объекты классов группы
_withassign следующим образом:
istream_withassign cin ;// соответствует stdin
ostream_withassign cout ;// соответствует stdout
ostream_withassign cerr ;// соответствует stderr
ostream_withassign clog ;// буферизованный cerr
В Microsoft Visual C++ предопределенные потоки cin, cout, cerr и clog инициализирует спеціально для
этого предназначенный статический класс iostream_init.
ПРЕИМУЩЕСТВА БИБЛИОТЕКИ ПОТОКОВ C++
Библиотека потоков C++ предоставляет несколько преимуществ в сравнении с функциями вводавывода
библиотеки времени выполнения.
Потоки вывода создаются на базе класса ostream, который обеспечивает методы для записи данных в
буфер потока. Перечислим основные методы класса ostream: operator<< форматированный вывод данных
в поток, flush очищает буфер, put выводит символ, seekp устанавливает позицию для функции put, tellp
читает позицию указателя для функции put, write пишет последовательность байтов, От класса ostream
наследуются класс ofstream, который содержит дополнительные методы: open открыть файл, close закрыть файл, is_open проверка открыт ли файл. Сейчас приведем прототипы этих функций и примеры
их использования. 1. Функции open, close и is_open имеют следующие прототипы: void open ( const char *
filename, openmode mode = out | trunc ); void close ( ); bool is_open ( ); При открытии потока вывода нужно
указать имя файла и режимы работы потока с этим файлом. При этом нужно запомнить, что режимы
работы с потоками ввода и вывода совпадают. Например, следующая программа добавляет предложение
в конец текстового файла и показывает, как использовать вышеперечисленные функции. 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 #include #include using namespace std; int main () { ofstream out; out.open ("test.txt",
ofstream::out | ofstream::app); if (out.is_open()) out << "This sentence is appended to the file content.\n"; else
cerr << "Open file failed." << endl; out.close(); return 0; } 2. Функцияflush очищает буфер. Эта функция
имеет следующий прототип: ostream& flush ( ); Ниже приведен пример использования функции flush.
Этот пример также показывает, как можно создавать текстовый файл 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16 17 18 19 #include int main () { ofstream out("test.txt"); for (int n=0; n<100; n++) { out << n << ' ';
out.flush(); } out << '\n'; // переход на новую строку for (n=0; n<100; n++) out << (n+0.1) << ' ' << flush; out
<< endl; // переход на новую строку out.close(); return 0; } 3. Функция put выводит символ в файл. Эта
функция имеет следующий прототип: ostream& put ( char ch ); В следующем примере показано, как
водить символы с консоли и выводить их в файл. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include
#include int main () { char ch; ofstream out("test.txt"); cout << "Input chars then input '.' to exit." << endl; do
{ ch = cin.get(); out.put(ch); } while (ch!='.'); return 0; } 4. Функция seekp устанавливает, а функция tellp
читает позицию в файле для функции put. Эти функции имеют следующие прототипы: streampos tellp ( );
ostream& seekp ( streampos pos ); где pos  новая позиция в потоке; ostream& seekp ( streamoff off,
ios_base::seekdir dir ); где параметры имеют следующее назначение: off смещение в потоке относительно
позиции, указанной в параметре dir. dir направление поиска позиции, может принимать одно из
следующих значений: ios_base::beg – поиск от начала файла; ios_base::cur  поиск от текущей позиции;
ios_base::end – поиск от конца файла. Ниже приведен пример использования этих функций. 1 2 3 4 5 6 7 8
9 10 11 12 13 14 15 16 17 18 #include int main () { long pos; ofstream out; out.open ("test.txt"); out << "This is
a string." << endl; pos=out.tellp(); out.seekp (pos  11); out << "an example."; out.close(); return 0; } 5.
Функция write пишет последовательность символов (байтов) в файл. Эта функция имеет следующий
прототип: ostream& write ( const char* s , size n ); где s указывает на область памяти, из которой данные
записываются в файл, а n – количество записываемых символов (байтов). Отметим, что эта функция
используется для записи данных в бинарные файлы, то есть содержимое области памяти записывается в
файл без изменения. Ниже приведен пример создания бинарного файла, используя функцию write. 1 2 3 4
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
43 44 45 46 #include #include struct emp { int code; char name[20]; double salary; }; int main() { ofstream out;
// выходной поток struct emp s; // для записей файла // открываем выходной поток в бинарном режиме
out.open("demo.bin", ofstream::binary); if(!out) { cerr << "Open file failed." << endl; return 1; } cout << "Input
code, name and salary." << endl; cout << "Press Ctrl+z to exit." << endl; cout << '>'; // вводим первую запись
с консоли cin >> s.code >> s.name >> s.salary; while (!cin.eof()) { // пишем запись в файл out.write((const
char*)&s, sizeof(struct emp)); cout << '>'; // вводим следующие записи с консоли cin >> s.code >> s.name >>
s.salary; } // закрываем выходной поток out.close(); return 0; } От класса ostream также наследуются класс
ostringstream, который обеспечивает интерфейс для работы со строками. Класс ostringstream содержит
дополнительный метод: str – чтение и запись строки в поток. 6. Функция str выполняет запись и чтение
строки в поток. Эта функция имеет следующий прототип: string str ( ) const чтение строки из потока void
str ( string & s ); запись строки s в поток Например, в следующей программе показано, как ввести строку
в поток типа ostringstream, а затем прочитать его содержимое в объект типа string. 1 2 3 4 5 6 7 8 9 10 11
12 13 14 15 16 17 18 19 20 #include #include #include using namespace std; int main () { ostringstream oss;
string s; oss.str("Sample string_1."); s = oss.str(); cout << s << endl; oss << "Sample string_2."; s = oss.str();
cout << s << endl; return 0; } 1.4. Потоки ввода. Потоки ввода являются объектами класса istream,
который обеспечивает методы для чтения информации из буфера потока. Перечислим основные методы
класса istream: operator >> форматированный ввод, gcount возвращает количество символов,
прочитанных последней операцией ввода, get ввод символа, getline ввод строки, ignore удаление
символов из буфера, peek читает символ, но не удаляет его из буфера, putback возвращает символ в
буфер, read читает блок данных, seekg устанавливает указатель позиции файла для метода get, sync синхронизирует буфер потока с внешним устройством, tellg получает указатель позиции файла для
метода get, unget возвращает символ в поток, От класса istream наследуется класс ifstream, который
обеспечивает интерфейс для работы с файлами. Класс ifstream содержит дополнительные методы: open
открыть файл, close закрыть файл, is_open проверить, открыт ли файл. Как работать с этими функциями,
было показано в предыдущем параграфе. Сейчас же подробно рассмотрим работу с функциями класса
istream. 1. Функция gcount возвращает количество символов, прочитанных последней не форматирующей
операцией ввода. Эта функция имеет следующий прототип: streamsize gcount ( ) const; К не
форматирующим операциям ввода относятся следующие операции: get, getline, ignore, read и readsome.
Пример использования функции gcount показан в следующей программе: 1 2 3 4 5 6 7 8 9 10 11 12 13 14
15 16 17 #include #include using namespace std; int main () { char line[80]; int length; cout << "Input a string:
" << endl; cin.getline(line, 80); length = cin.gcount(); cout << "String length = " << length1 << endl; return
0; } 2. Функция get вводит символ из входного потока. Эта функция имеет следующий прототип: int get();
возвращает символ, извлеченный из потока; istream& get (char& c ); извлекает символ из потока и
сохраняет его в переменной с; istream& get (char* s, streamsize n, char delim = ‘\n’ ); вводит из потока
символы и записывает их в массив s, ввод символов прекращается в следующих случаях:  если введен (n
1) символ;  если в потоке встретился символ разделитель delim, сам символ разделитель из потока не
извлекается;  файл закончился раньше, чем прочитан (n1) символ. После записи прочитанных символов
в массив s функция get записывает в этот массив пустой символ NULL, отмечающий конец строки. Ниже
приведена программа, которая распечатывает содержимое текстового файла. 1 2 3 4 5 6 7 8 9 10 11 12 13
14 15 16 17 #include #include using namespace std; int main () { ifstream in; in.open ("test.txt", ifstream::in);
while (in.good()) cout << (char) in.get(); cout << endl; in.close(); return 0; } А теперь приведена программа,
которая читает символы из входного потока, используя функцию get. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23 24 25 26 #include int main () { char c; char a[3]; cout << "Input a char: "; c = cin.get();
cout << c << endl; cin.get(); // удаляем символ конца строки cout << "Input a char: "; cin.get(c); cout << c <<
endl; cin.get(); // удаляем символ конца строки cout << "Input a string: "; cin.get(a, 3); cout << endl << "The
first two symbols: "; cout << a << endl << endl; return 0; } 3. Функция getline вводит строки из файла. Эта
функция имеет следующий прототип: istream& getline (char* s, streamsize n, char delim = ‘\n’); вводит из
потока символы и записывает их в массив s, ввод символов прекращается в следующих случаях:  если
введен (n1) символ;  если в потоке встретился символ разделитель delim, причем сам символ
разделитель извлекается из потока, но не записывается в массив s;  файл закончился раньше, чем
прочитан (n1) символ. После записи прочитанных символов в массив s функция getline записывает в этот
массив пустой символ NULL, отмечающий конец строки. Ниже приведена программа, которая вводит
строки из потока и распечатывает их на консоли. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include int
main () { char line[80]; cout << "Input strings. " << endl; cout << "To exit press CTRL+Z." << endl; cout <<
'>'; while (!cin.eof()) { cin.getline(line, 80); cout << ' ' << line << endl; cout << '>'; } return 0; } 4. Функция
ignore удаляет символы из буфера потока. Эта функция имеет следующий прототип: istream& ignore
( streamsize n = 1, int delim = EOF ); где n – количество символов, которые необходимо удалить из
потока, а delim – это символ ограничитель. Функция удаляет символы из потока до тех пор, пока не
удалит n символов или не встретит символ разделитель. Например, в следующей программе выводятся
только первые символы введенных слов. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#include using namespace std; int main () { char c; cout << "Input a word: "; c = cin.get(); cin.ignore(256,'\n');
cout << "The first letter is: " << c << endl; cout << "Input another word: "; cin.ignore(); c = cin.get();
cin.ignore(256,'\n'); cout << "The second letter is: " << c << endl; return 0; } 5. Функция peek читает символ,
но не удаляет его из буфера. Эта функция имеет следующий прототип: int peek ( ); возвращает
прочитанный символ, а если файл закончился или в потоке произошла ошибка, то возвращает EOF. Ниже
приведена программа, в которой используется функция peek. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
19 20 21 22 23 24 #include using namespace std; int main () { char c; int n; char s[256]; cout << "Enter a
number or a word: "; c = cin.peek(); if ( (c >= '0') && (c <= '9') ) { cin >> n; cout << "It is a number: " << n <<
endl; } else { cin >> s; cout << "It is a word: " << s << endl; } return 0; } 6. Функция putback возвращает
символ в буфер. Эта функция имеет следующий прототип: istream& putback (char ch ); если введенный
символ совпадает с символом ch, то функция возвращает его в буфер ввода, иначе поведение функции
непредсказуемо. Использование функции putback показано в следующей программе. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include using namespace std; int main () { char c; int n; char
s[256]; cout << "Enter a number or a word: "; c = cin.get(); cin.putback (c); if ( (c >= '0') && (c <= '9') ) { cin
>> n; cout << "It is a number: " << n << endl; } else { cin >> s; cout << " It is a word: " << s << endl; } return
0; } 7. Функция read читает блок данных из файла и имеет следующий прототип: istream& read (char* s,
streamsize n ); где s указывает на область памяти, в которую данные читаются из файла, а n – количество
читаемых символов (байтов). Отметим, что эта функция используется для чтения данных из бинарных
файлов, то есть содержимое файла без изменения читается в область памяти. Ниже приведен пример
чтения записей бинарного файла, используя функцию read. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
56 57 58 // чтение бинарного файла #include #include struct emp { int code; char name[20]; double salary; };
int main() { ifstream in; // выходной поток struct emp s; // для записей файла unsigned i; // номер записи //
открываем входной поток в бинарном режиме in.open("demo.bin"); if(!in) { cout << "Open file failed.\n";
return 1; } cout << "Press Ctrl+z to exit.\n"; // читаем индекс cout << "Input an index: "; cin >> i; while (!
cin.eof()) { // устанавливает указатель на нужную запись in.seekg(i*sizeof(struct emp)); // читаем запись из
файла in.read((char*)&s, sizeof(struct emp)); if (!in.good()) { cout << "The wrong index.\n"; cout << "Input an
index: "; cin >> i; in.clear(); // очищаем ошибку continue; } // выводим запись на консоль cout << "\tcode = "
<< s.code << " name = " << s.name << " sal = " << s.salary << endl, // читаем индекс cout << "Input an index:
"; cin >> i; } // закрываем входной поток in.close(); return 0; } 8. Функция seekg устанавливает указатель
позиции файла для метода get, а функция tellg получает указатель позиции файла для метода get. Эти
функции имеют следующие прототипы: istream& seekg ( streampos pos ); устанавливает позицию файла на
значение pos, тип streampos эквивалентен типу long. istream& seekg ( streamoff off, ios_base::seekdir dir );
сдвигает позицию файла на значение off относительно значения параметра dir, который может принимать
следующие значения: ios_base::beg смещение относительно начала файла; ios_base::cur смещение
относительно текущей позиции; ios_base::end смещение относительно конца файла. streampos tellg ( );
возвращает указатель позиции файла для функции get, тип streampos эквивалентен типу long. Ниже
приведена программа, которая демонстрирует использование вышеуказанных функций. 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 //
чтение файла в память #include #include struct emp { int code; char name[20]; double salary; }; int main ()
{ int length; emp* buffer; ifstream in; in.open("demo.bin", ios::binary); if (!in) { cout << "Open file failed" <<
endl; return 1; } // определеям длину файла in.seekg(0, ios::end); length = in.tellg(); in.seekg(0, ios::beg); //
распределяем память под файл buffer = (emp*) new char[length]; // читаем файл
in.read((char*)buffer,length); in.close(); // выводим содержимое на консоль for (int i=0; i<<=""
buffer[i].code="" '="" buffer[i].name="" buffer[i].salary="" endl;="" return="" 0;="" }="" 9.="" Функция=""
sync="" синхронизирует="" буфер="" потока="" с="" внешним="" устройством.="" Эта="" функция=""
имеет="" следующий="" прототип:="" int="" (="" );="" Как="" работает="" эта="" функция,="" и=""
что="" такое="" синхронизация="" буфера="" устройством="" смотри="" в="" параграфе="" 1.6.=""
10.="" unget="" возвращает="" поток="" символ,="" предварительно="" извлеченный="" из="" потока.=""
unget();="" Ниже="" приведена="" программа,="" которой="" показано="" использование="" функции=""
unget.="" 1="" 2="" 3="" 4="" 5="" 6="" 7="" 8="" 9="" 10="" 11="" 12="" 13="" 14="" 15="" 16="" 17=""
18="" 19="" 20="" 21="" 22="" 23="" 24="" 25="" 26="" #include="" using namespace std; int main () { char
c; int n; char s[256]; cout << "Enter a number or a word: "; c = cin.get(); cin.unget(); if ( (c >= '0') && (c <= '9')
) { cin >> n; cout << "It is a number: " << n << endl; } else { cin >> s; cout << "It is a word: " << s << endl; }
return 0; } От класса istream наследуется класс istringstream, который обеспечивает интерфейс для
работы со строками. Класс istringstream содержит дополнительный метод: str чтение или запись строки в
поток. 11. Функция str для записи и чтения строки в поток. Прототипы этой функции были рассмотрены
в предыдущем параграфе пункт 6. Сейчас же приведем только программу, в которой показано, как
записать строку в поток типа istringstream, а затем вывести содержимое этого потока. 1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20 #include #include #include using namespace std; int main () { int n;
istringstream iss; string s = "0 1 2"; iss.str(s); for (int i = 0; i < 3; ++i) { iss >> n; cout << n + 1 << endl; }
return 0; } 1.5. Потоки вводавывода. Потоки вводавывода создаются на базе класса iostream, который
является производным классом от классов istream и ostream и поэтому наследует все их методы. Для
работы с файлами и со строками из класса iostream наследуются соответственно классы fstream и stringstream, которые позволяют, как писать данные в потоки, так и читать данные из потоков. Для
наглядного представления отношения наследования между этими классами смотри диаграмму
наследования в параграфе 1.1. Здесь же заметим, что заголовочный файл содержит потоки вводавывода:
cin, cout, cerr и clog, примеры работы с которыми смотри в параграфе 1.8.
Источник: http://www.itmathrepetitor.ru/slekciya9rabotaspotokamivs/

file_name: тема 2 вопрос 35.docx

description:
тема 2 вопрос 35
потоки ввода вывода в с++ классы потоков операции помещения в поток и извлечения из потока
примеры
Главным преимуществом системы вводавывода C++ является то, что она может перегружаться для
создаваемых классов.
Поток вводавывода – это логическое устройство, предназначенное для приема и выдачи информации
пользователю. Поток связан с физическим устройством с помощью системы вводавывода C++. Поток
обеспечивает пользователю единый интерфейс при работе с системой вводавывода. Это означает, что,
например, для вывода информации на экран монитора и для записи ее в файл используется одна и та же
функция.
Когда программа на C++ начинает выполняться, автоматически создаются восемь предопределенных
стандартных потоков. Эти стандартные потоки связаны со стандартными файлами языка C следующим
образом:
поток для "узких" символов cin cout cerr clog
поток для "широких" символов wcin wcout wclog
стандартный файл языка C stdin stdout stderr stderr
Объект cinуправляет вводом из буфера потока, связанного с объектом stdin, объявленным в <cstdio>. По
умолчанию эти два потока синхронизированы.
Объект cout управляет буфером потока, связанным с объектом stdout, объявленным в <cstdio>. По
умолчанию эти два потока также синхронизированы.
Поток clog – это просто буферизованная версия потока cerr. В буферизованной версии потока запись на
реальное внешнее устройство делается, только когда буфер полон. Поэтому clog является более
эффективным для перенаправления вывода в файл, в то время как cerr используется главным образом
для вывода на экран терминала.
Система вводавывода содержит две иерархии классов: первая предназначена для работы с ASCII
символами, имеющими длину 8 бит; вторая предназначена для работы с UNICODEсимволами,
имеющими длину 16 бит.
Символы первого набора называются "узкими", а второго – "широкими".
В основе иерархии потоковых классов лежит класс basic_ios.
Класс basic_ios является базовым для нескольких производных классов, среди которых классы
basic_istream, basic_ostream и basic_iostream. Он содержит наиболее общие функции, необходимые для
всех потоков, и обслуживает информацию о состоянии, которая отражает целостность потока и буфер
потока. Классы, производные от basiс_ios, специализируют операции вводавывода. В свою очередь,
basic_ios использует класс ios_base, который также является базовым классом для всех потоковых
классов. Он не зависит от типа символов и инкапсулирует информацию, необходимую для всех потоков.
Этот класс определяет несколько типов данных, используемых всеми потоковыми классами, такие как
флаги форматирования, биты состояния, режимы открытия файлов и т.д.
С целью обеспечения совместимости с традиционной версией библиотеки вводавывода C++ введены
синонимы для имен потоковых классов:
Шаблон класса
Синоним
Шаблон класса
Синоним
basic_ios basic_ifstream
ifstream
basic_istream
basic_ofstream
ofstream
basic_оstream
оstream
basic_fstream
basic_streambuf
iostream
basic_iostream
streambuf

description:
Имена синонимов в точности соответствуют именам потоковых классов в традиционной версии
библиотеки вводавывода C++. Далее при изложении потокового вводавывода и мы будем пользоваться
этими именами, поскольку как раз эти имена следует указывать в программах.
Библиотека вводавывода содержит два параллельных семейства классов: одно – производное от
streambuf и второе – производное от ios. Оба эти класса являются низкоуровневыми, выполняющими
различный вид задач. Все потоковые классы имеют, по крайней мере, один из этих классов в качестве
базового. Доступ из iosпроизводных классов к streambufпроизводным осуществляется через указатель.
Класс streambuf обеспечивает интерфейс с памятью и физическими устройствами. Функциичлены
семейства классов streambuf используются iosпроизводными классами.
Назначение классов потокового вводавывода следующее:
istreamпотоковый класс общего назначения для ввода, являющийся базовым классом для других
потоков ввода;
ifstreamпотоковый класс для ввода из файла;
istream_withassignпотоковый класс ввода для cin;
istrstrearmпотоковый класс для ввода строк;
оstreamпотоковый класс общего назначения для вывода, являющийся базовым классом для других
потоков вывода;
ofstreamпотоковый класс для вывода в файл;
ostream_withassignпотоковый класс ввода для cout, cerr, clog;
ostrstreamпотоковый класс для вывода строк;
iostreamпотоковый класс общего назначения для вводавывода, являющийся базовым классом для
других потоков вводавывода;
fstreamпотоковый класс для вводавывода в файл;
strstreamпотоковый класс для вводавывода строк;
stdiostreamкласс для вводавывода в стандартные файлы вводавывода;
streambufабстрактный базовый класс буфера потока;
filebufкласс буфера потока для дисковых файлов;
strstreambufкласс буфера потока для строк;
stdiobufкласс буфера потока для стандартных файлов вводавывода.
Назначение почти всех классов следует из их названия. Классы группы _withassign являются
производными соответствующих потоковых классов без этого окончания. Они перегружают оператор
присваивания, что позволяет изменять указатель на используемый классом буфер. Если подключен
заголовочный файл <iostream>, программы, написанные на языке C++, начинают выполняться с
четырьмя открытыми предопределенными потоками, объявленными как объекты классов группы
_withassign следующим образом:
istream_withassign cin ;// соответствует stdin
ostream_withassign cout ;// соответствует stdout
ostream_withassign cerr ;// соответствует stderr
ostream_withassign clog ;// буферизованный cerr
В Microsoft Visual C++ предопределенные потоки cin, cout, cerr и clog инициализирует спеціально для
этого предназначенный статический класс iostream_init.
ПРЕИМУЩЕСТВА БИБЛИОТЕКИ ПОТОКОВ C++
Библиотека потоков C++ предоставляет несколько преимуществ в сравнении с функциями вводавывода
библиотеки времени выполнения.
Потоки вывода создаются на базе класса ostream, который обеспечивает методы для записи данных в
буфер потока. Перечислим основные методы класса ostream: operator<< форматированный вывод данных
в поток, flush очищает буфер, put выводит символ, seekp устанавливает позицию для функции put, tellp
читает позицию указателя для функции put, write пишет последовательность байтов, От класса ostream
наследуются класс ofstream, который содержит дополнительные методы: open открыть файл, close

title: Лекция "Потоки ввода вывода в с++ "


extracted_text:
тема 3 вопрос 1
Требования к ос. классификация ос
Основы операционных систем (ОС). Назначение и функции ОС. Классификация ОС.
Требования к ОС.
Операционная   система  (ОС)    часть  программного  обеспечения,  выступающая   в  качестве
интерфейса между приложениями (и
пользователями) и аппаратурой компьютера.
Операционная система выполняет две основные функции:
-
Предоставление   пользователюпрограммисту   вместо   реальной   аппаратуры
компьютера   расширенной   виртуальной   машины,   с   которой   удобнее   работать.   Виртуальная
машина      это   вычислительная   система   заданной   конфигурации,   моделируемая   для
пользователя программными и аппаратными средствами конкретного реально существующего
компьютера. Операционная система является тем слоем программного обеспечения, которое
преобразует аппаратную машину в виртуальную.
-
Повышение   эффективности   использования   компьютера   за   счет   рационального
управления его ресурсами. Ресурсы операционной системы можно разделить на две группы:
программные   ресурсы   (процессы,   виртуальное   адресное   пространство,   подсистема   ввода
вывода); аппаратные ресурсы (процессоры, память, устройства).
Операционная система (ОС)  это упорядоченная последовательность системных управляющих
программ совместно с необходимыми информационными массивами, предназначенная для
планирования исполнения пользовательских программ и управления всеми ресурсами
вычислительной машины (программами, данными, аппаратурой, и др.) с целью предоставления
возможности пользователям эффективно (в некотором смысле) решать задачи,
сформулированные в терминах вычислительной системы. Вообще, ОС  это довольно
расплывчатое понятие, опирающееся на определенные традиции, параметры оборудования,
размеры программ, реализующих определенные функции, а также распределение обеспечивать
загрузку пользовательских программ в оперативную память и их исполнение обеспечивать
работу с устройствами долговременной памяти, такими как магнитные диски, ленты,
оптические диски и т.д. Как правило, ОС управляет свободным пространством на этих
носителях и структурирует пользовательские данные предоставлять более или менее
стандартный доступ к различным устройствам ввода/вывода, таким как терминалы, модемы,
печатающие устройства предоставлять некоторый пользовательский интерфейс. Слово
некоторый здесь сказано не случайно  часть систем ограничивается командной строкой, в то
время как другие на 90% состоят из средств интерфейса пользователя Существуют ОС,
функции которых этим и исчерпываются. Одна из хорошо известных систем такого типа
дисковая операционная система MS DOS. Более развитые ОС предоставляют также
следующие возможности: параллельное (точнее, псевдопараллельное, если машина имеет
только один процессор) исполнение нескольких задач распределение ресурсов компьютера
между задачами организация взаимодействия задач друг с другом взаимодействие
пользовательских программ с нестандартными внешними устройствами организация
межмашинного взаимодействия и разделения ресурсов защита системных ресурсов, данных и
программ пользователя, исполняющихся процессов и самой себя от ошибочных и зловредных
действий пользователей и их программ Назначение операционной системы Операционная
система (ОС)  это комплекс программного обеспечения, предназначенный для снижения
стоимости программирования, упрощения доступа к системе, повышения эффективности
работы. Цель создания операционной системы  получить экономический выигрыш при
использовании системы, путем увеличения производительности труда программистов и
эффективности работы оборудования. Функции операционной системы:  связь с
пользователем в реальном времени для подготовки устройств к работе, переопределение
конфигурации и изменения состояния системы.  выполнение операций вводавывода; в
частности, в состав операционной системы входят программы обработки прерываний от
устройств вводавывода, обработки запросов к устройствам вводавывода и распределения этих запросов между устройствами.  управление памятью, связанное с распределением
оперативной памяти между прикладными программами.  управление файлами; основными
задачами при этом являются обеспечение защиты, управление выборкой и сохранение
секретности хранимой информации.  обработка исключительных условий во время
выполнения задачи  появление арифметической или машинной ошибки, прерываний,
связанных с неправильной адресацией или выполнением привилегированных команд.
вспомогательные, обеспечивающие организацию сетей, использование служебных программ и
языков высокого уровня. Вверх Вариантов классификации ОС может быт очень много, они
зависят от признака, по которому одна ОС отличается от другой:  по назначению;  по режиму
обработки;  по способу взаимодействия с системой;  по способу построения. Основным
предназначением ОС является:  организация эффективных и надежных вычислений;
создание различных интерфейсов для взаимодействия с этими вычислениями и самой
вычислительной системой. ОС разделяют по назначению:  ОС общего назначения;  ОС
специально назначения. ОС специального назначения подразделяются на следующие:  для
переносимых компьютеров и встроенных систем;  для организации и ведения баз данных;
для решения задач реального времени и т.д. ОС разделяют по режиму обработки задач:
однопрограммный режим;  мультипрограммный режим. Мультипрограммирование – способ
организации вычислений, когда на однопроцессной вычислительной системе создается
видимость одновременного выполнения нескольких задач. Любая задержка в выполнении
одной программы используется для выполнения других программ. Мультипрограммный и
многозадачный режимы близки по смыслу, но синонимами не являются. Мультипрограммный
режим обеспечивает параллельное выполнение нескольких приложений, а программисты,
создающие эти приложения, не должны заботиться о механизме организации их параллельной
работы. Эти функции выполняет ОС, которая распределяет между выполняющимися
приложениями ресурсы вычислительной системы, обеспечивает необходимую синхронизацию
вычислений и взаимодействие. Мультизадачный режим предполагает, что забота о
параллельном выполнении и взаимодействии приложений ложится на прикладных
программистов. Современные ОС для ПК реализуют и мультипрограммный, и многозадачный
режимы. По организации работы в диалоговом режиме ОС делятся на следующие:
однопользовательские (однотерминальные);  мультитерминальные. В мультитерминальных ОС
с одной вычислительной системой одновременно могут работать несколько пользователей,
каждый со своего терминала, при этом у пользователей возникает иллюзия, что у него имеется
своя собственная вычислительная система. Для организации мультитерминального доступа
необходим мультипрограммный режим работы вычислительной системы. Основная
особенность операционных систем реального времени (ОСРВ) – обеспечение обработки
поступающих заданий в течение заданных интервалов времени, которые нельзя превышать.
Поток заданий не является планомерным и не регулируется оператором, т.е. задания
поступают в непредсказуемые моменты времени и без всякой очередности. В ОСРВ в общем
случае отсутствуют накладные расходы процессорного времени на этап инициирования
(загрузку программы, выделение ресурсов), так как набор задач обычно фиксирован и вся
информация о задаче известна до поступления запроса. Для реализации режима реального
времени необходим режим мультипрограммирования, который является основным средством
повышения производительности вычислительной системы, а для задач реального времени
производительность – решающий фактор. Лучшие по производительности характеристики для
систем реального времени обеспечивают однотерминальные ОСРВ. По способам построения
(архитектуре) ОС подразделяются на следующие:  микроядерные;  монолитные. Это деление
условно. К микроядерным ОС относится ОСРВ QNX, а к монолитным – Windows 9x и Linux.
Для ОС Windows 9x пользователь не может изменить ядро, так как не располагает исходными
кодами и программой сборки ядра. Для ОС Linux такая возможность предоставлена,
пользователь может сам собрать ядро, включив в него необходимые программные модули и
драйверы. Сегодня к ОС предъявляется множество требований. Главными из них, конечно же,
являются выполнение функций эффективного управления ресурсами вычислительной системы
и обеспечение удобного интерфейса для пользователя и прикладных программ. Кроме того,
можно выделить ряд основных требований, которым должна удовлетворять любая современная ОС. Производительность. ОС должна обладать настолько хорошим
быстродействием и временем реакции, насколько это позволяет аппаратная платформа. На
производительность ОС оказывает влияние множество факторов, среди которых основными
являются архитектура ОС, многообразие реализуемых ею функций, количество ресурсов,
потребляемых самой ОС для выполнения поставленных перед ней задач, качество
программного кода. Надежность. Это требование ОС определяется архитектурными
решениями, положенными в ее основу, а также качеством реализации, обратно
пропорциональным количеству ошибок в комплексе программ, составляющих ОС.
Защищенность. Система должна быть защищена как от внутренних, так и от внешних ошибок,
сбоев и отказов. Ее действия должны быть всегда предсказуемы, а приложения не должны
иметь возможности наносить вред. Современная ОС защищает данные и другие ресурсы
вычислительной системы от несанкционированного доступа и от попыток непреднамеренного
повреждения этих данных. Расширяемость. ОС является расширяемой, если в нее можно
вносить дополнения и изменения, не нарушая целостности системы. Расширяемость
достигается за счет модульной структуры ОС, при которой программы строятся из отдельных
модулей, взаимодействующих только через функциональный интерфейс. Такая архитектура
позволяет в случае необходимости добавлять новые или удалять ненужные компоненты.
Однако простота, с которой пользователь или системный программист сможет производить
такие функциональные изменения, определяется совершенством и продуманностью
применяемых при построении системы решений. Переносимость. В идеальном случае ОС
должна легко переноситься с одного типа аппаратной платформы на другой. Реально это
далеко не всегда быстро и легко выполнимая задача. Как правило, ОС разрабатывается для
определенного типа аппаратных платформ и перенос ее на платформу с принципиально иным
строением может стать трудной задачей. Совместимость. ОС всегда изменяются со временем,
и эти изменения более значимы, чем изменения аппаратных средств. Изменения ОС обычно
заключаются в приобретении ими новых свойств, добавлении новых и модификации
имеющихся функций. Под требованием совместимости понимается сохранение возможности
использования прикладных программ, написанных для “старой” или вообще другой ОС, в
новой ОС. Удобство. Средства ОС должны быть простыми и гибкими, а логика ее работы ясна
пользователю. Современные ОС ориентированы на обеспечение пользователю максимально
возможного удобства при работе с ними. Необходимым условием этого стало наличие у ОС
графического пользовательского интерфейса и всевозможных мастеров – программ,
автоматизирующих установку, настройку и эксплуатацию системы. В зависимости от области
применения конкретной ОС изменяется и состав предъявляемых к ней требований.
4.3 Классификация ОС.
ОС классифицируются по следующим принципам:
1) По количеству одновременно существующих программных процессов ОС делятся на
однопрограммные  и  мультипрограммные.   В   мультипрограммных   ОС,   в   отличие   от
однопрограммных,     вычислительный   процесс   организуется   таким   образом,   что   в   памяти
компьютера находится одновременно несколько программ, попеременно выполняющихся на
одном   процессоре.   Такая   организация   позволяет   значительно   повысить   эффективность
вычислительной системы.
2)  По   числу  пользователей,   осуществляющих   доступ   к   вычислительной   системе,
различают  однопользовательские  и  многопользовательские  ОС.   Многопользовательские
системы   предоставляют   возможность   одновременного   доступа   к   вычислительной   системе
нескольким пользователям. При этом каждый из них работает за собственным терминалом,
однако   все   вычисления   производятся   на   одном   компьютере.   Это   приводит   к   более
эффективному использованию вычислительной техники и уменьшению стоимости обработки
данных.
3)
 универсальные  и  специализированные.
Специализированные   ОС,   как   правило,   работают   с   фиксированным   набором   программ.
Применение таких систем обусловлено невозможностью использования универсальной ОС по
соображениям эффективности, а также вследствие специфики решаемых задач.
 По
 назначению  ОС   делятся   на 4)  По  способу   загрузки  можно   выделить  загружаемые  ОС   и  системы,   постоянно
находящиеся в памяти вычислительной системы. Последние, как правило, используются для
управления работой  специализированных устройств.
  5)  По  особенности области использования  ОС подразделяются  на системы пакетной
обработки, системы разделения времени и системы реального времени. Системы пакетной
обработки   предназначаются   в   основном   для   решения   задач   вычислительного   характера,   не
требующих   быстрого   получения   результатов.   Критерием   эффективности   таких   систем
является максимальная пропускная способность, то есть решение максимального числа задач в
единицу времени. Взаимодействие пользователя с вычислительной системой сводится к тому,
что он приносит задание, отдает его оператору, а через некоторое время, после выполнения
пакета заданий, получает результат.
4.4 Требования к ОС.
Сегодня   к   ОС   предъявляется   множество   требований.   Главными   из   них,   конечно   же,
являются выполнение функций эффективного управления ресурсами вычислительной системы
и обеспечение удобного интерфейса для пользователя и прикладных программ. Кроме того,
можно выделить ряд основных требований, которым должна удовлетворять любая современная
ОС.
1)   Производительность.   ОС   должна   обладать   настолько   хорошим   быстродействием   и
временем реакции, насколько это позволяет аппаратная платформа. На производительность ОС
оказывает влияние множество факторов, среди которых основными являются архитектура ОС,
многообразие реализуемых ею функций, количество ресурсов, потребляемых самой ОС для
выполнения поставленных перед ней задач, качество программного кода.
2)   Надежность.   Это   требование   ОС   определяется   архитектурными   решениями,
положенными     в   ее   основу,   а   также   качеством   реализации,   обратно   пропорциональным
количеству ошибок в комплексе программ, составляющих ОС.
3) Защищенность. Система должна быть защищена как от внутренних, так и от внешних
ошибок, сбоев и отказов. Ее действия должны быть всегда предсказуемы, а приложения не
должны   иметь   возможности   наносить   вред.   Современная   ОС   защищает   данные   и   другие
ресурсы   вычислительной   системы   от   несанкционированного   доступа   и   от   попыток
непреднамеренного повреждения этих данных.
4) Расширяемость. ОС является расширяемой, если в нее можно вносить дополнения и
изменения, не нарушая целостности системы. Расширяемость достигается за счет модульной
структуры ОС, при которой программы строятся из отдельных модулей, взаимодействующих
только   через   функциональный   интерфейс.   Такая   архитектура   позволяет   в   случае
необходимости   добавлять   новые   или   удалять   ненужные   компоненты.   Однако   простота,   с
которой пользователь или системный программист сможет производить такие функциональные
изменения,   определяется   совершенством   и   продуманностью   применяемых   при   построении
системы решений.
5) Переносимость. В идеальном случае ОС должна легко переноситься с одного типа
аппаратной платформы на другой. Реально это далеко не всегда быстро  и легко выполнимая
задача. Как правило, ОС разрабатывается для определенного типа аппаратных платформ и
перенос ее на платформу с принципиально иным строением может стать трудной задачей.
6) Совместимость. ОС всегда изменяются со временем, и эти изменения более значимы,
чем изменения аппаратных средств. Изменения ОС обычно заключаются в приобретении ими
новых   свойств,   добавлении   новых   и   модификации   имеющихся   функций.   Под   требованием
совместимости   понимается   сохранение   возможности   использования   прикладных   программ,
написанных для “старой” или вообще другой ОС, в новой ОС.
7) Удобство. Средства ОС должны быть простыми и гибкими, а логика ее работы  ясна
пользователю.   Современные   ОС   ориентированы   на   обеспечение   пользователю   максимально
возможного удобства при работе с ними. Необходимым условием этого стало наличие у ОС
графического   пользовательского   интерфейса   и   всевозможных   мастеров   –   программ,
автоматизирующих установку, настройку и эксплуатацию системы. В зависимости от области применения конкретной ОС изменяется и состав предъявляемых к
ней требований.

file_name: тема 3 вопрос 1.docx

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

title: Лекция "Требования к ос. "