Ответы на билеты (билет 13)

Посмотреть архив целиком

1) Если мы используем выходной поток cout, мы помещаем данные в поток с помощью оператора вставки (<<). Класс ios входит в состав библиотеки iostream.h

Функцию-член flags ( mask | flags() ) служит для установки битов, указанных параметром mask, и возвращает предыдущие значения, принадлежит к классу ios.

Функция-член setf() класса ios позволяет установить значение одного или нескольких флагов.

2) Основные итераторы

Основные итераторы используются наиболее часто. И вы будете сталкиваться с ними постоянно. Поэтому с их рассмотрения мы и начнем.

Основные итераторы взаимозаменяемы. Однако при этом нужно соблюдать иерархию старшинства (рис. 1).

Рис. 1.

Итераторы ввода

Итераторы ввода (input iterator) стоят в самом низу иерархии итераторов. Это наиболее простые из всех итераторов STL, и доступны они только для чтения. Итератор ввода может быть сравнен с другими итераторами на предмет равенства или неравенства, чтобы узнать, не указывают ли два разных итератора на один и тот же объект. Вы можете использовать оператор разыменовывания (*) для прочтения содержимого объекта, на который итератор указывает. Перемещаться от первого элемента, на который указывает итератор ввода, к следующему элементу можно с помощью оператора инкремента (++). Итераторы ввода возвращает только шаблонный класс istream_iterator. Однако, несмотря на то что итераторы ввода возвращаются единственным классом, ссылки на него присутствуют повсеместно. Это связано с тем, что вместо итератора ввода может подставляться любой из основных итераторов, за исключением итератора вывода, назначение которого прямо противоположно итератору ввода.

Проиллюстрируем это на примере алгоритма for_each. Если вы использовали ранее библиотеку контейнеров Borland BIDS, то операция for_each вам уже знакома. В STL она реализована следующим алгоритмом:

template

Function for_each (InputIterator first, InputIterator last, Function f)

{

while (first != last) f(*first++);

return f;

}

В этом примере итератор ввода выступает как первый параметр, указывающий на начало цепочки объектов, а второй параметр - также итератор ввода - это значение "за пределом" для этой цепочки. Тело алгоритма выполняет переход от объекта к объекту, вызывая для каждого значения, на которое указывает итератор ввода first, функцию. Указатель на нее передается в третьем параметре. Здесь задействованы все три перегруженных оператора, допустимые для итераторов ввода: сравнения (!=), инкремента (++) и разыменовывания (*). Так что лучше примера и не найти. В качестве первого и второго аргументов алгоритма сгодятся даже обычные указатели, о чем уже было сказано. Проиллюстрируем это. Пусть у нас имеется массив чисел, которые нужно распечатать. Тогда программа печати с использованием for_each может выглядеть так:

#include

#include

#pragma warning (disable: 4550)

using namespace std;

void printValue(int num)

{

cout << num << "\n";

}

main(void)

{

int init[] = {1, 2, 3, 4, 5};

for_each(init, init + 5, printValue);

}

Программа чрезвычайно проста. Есть массив init с пятью числами. Вызывается алгоритм for_each, ему в качестве входных итераторов передаются указатели на начало массива и на адрес, следующий за концом массива, т. е. на значение "за пределами". Третьим параметром является указатель на функцию printValue, которая печатает элементы массива. Чтобы включить в программу возможность использования потоков, добавляется включаемый файл iostream, а для описания прототипа алгоритма for_each в программу включается заголовочный файл algorithm (algorith для продуктов Borland). Обязательным при использовании STL является использование директивы:

using namespace std,

включающей пространство имен библиотеки STL. Поскольку пример изготовлен в среде компилятора Microsoft Visual C++ 5.0, была добавлена следующая директива:

#pragma warning (disable: 4550)

Она отключает назойливое предупреждение об отсутствии параметров, что, впрочем, ни на скорость (ни на зарплату!), конечно, не влияет, так что эту строку вполне можно опустить.

Итераторы вывода

Если итератор ввода предназначен для чтения данных, то итератор вывода (output iterator) служит для ссылки на область памяти, куда выводятся данные. Итераторы вывода можно встретить повсюду, где происходит хоть какая-то обработка информации средствами STL. Это могут быть алгоритмы (aлгоритмы STL - специальные блоки кода, выполняющие определенные операции по обработке данных) копирования, склейки и т. п. Для данного итератора определены операторы присвоения (=), разыменовывания (*) и инкремента (++). Однако следует помнить, что первые два оператора предполагают, что итератор вывода располагается в левой части выражений, т. е. во время присвоения он должен быть целевым итератором, которому присваиваются значения. Разыменовывание нужно делать лишь для того, чтобы присвоить некое значение объекту, на который итератор ссылается. Итераторы ввода могут быть возвращены итераторами потоков вывода (ostream_iterator) и итераторами вставки inserter, front_inserter и back_inserter (описаны в разделе "Итераторы вставки").

Ниже приведен типичный пример использования итераторов вывода:

#include

#include

#include

using namespace std;

main(void)

{

int init1[] = {1, 2, 3, 4, 5};

int init2[] = {6, 7, 8, 9, 10};

vector v(10);

merge(init1, init1 + 5, init2, init2 + 5, v.begin());

copy(v.begin(), v.end(), ostream_iterator(cout, "\n"));

}

В отличие от предыдущего примера, здесь, помимо потоков и алгоритмов, использован контейнер (kонтейнеры STL - структуры данных для хранения информации определенным способом) типа "вектор", т. е. одномерный массив. У него имеются специальные методы begin() и end(), задача которых - возвращать итератор, указывающий на начало вектора и значение "за пределом" соответственно. В приведенном нами примере создаются и инициализируются два массива - init1 и init2. Далее их значения соединяются вместе алгоритмом merge и записываются в вектор. А для проверки полученного результата мы пересылаем данные из вектора в поток вывода, для чего вызываем алгоритм копирования copy и специальный итератор потока вывода ostream_iterator. Он перешлет данные в поток cout, разделив каждое пересылаемое значение символом окончания строки. Для шаблонного класса ostream_iterator требуется указать тип выводимых значений. В нашем случае это int.

С этим примером вы можете проделать эксперимент, чтобы узнать, к чему приводит обращение к значению по адресу "за пределом". Для этого достаточно сделать вектор размером не 10, а 9 элементов:

vector v(9);

3) Виртуальный метод (виртуальная функция) — в объектно-ориентированном программировании метод (функция) класса, который может быть переопределён в классах-наследниках так, что конкретная реализация метода для вызова будет определяться во время исполнения. Таким образом, программисту необязательно знать точный тип объекта для работы с ним через виртуальные методы: достаточно лишь знать, что объект принадлежит классу или наследнику класса, в котором метод объявлен.

Виртуальные методы — один из важнейших приёмов реализации полиморфизма. Они позволяют создавать общий код, который может работать как с объектами базового класса, так и с объектами любого его класса-наследника. При этом, базовый класс определяет способ работы с объектами и любые его наследники могут предоставлять конкретную реализацию этого способа. В некоторых языках программирования, например в Java, все функции-члены класса, кроме статических, являются виртуальными.

Базовый класс может и не предоставлять реализации виртуального метода, а только декларировать его существование. Такие методы без реализации называются «чисто виртуальными» (калька с англ. pure virtual) или абстрактными. Класс, содержащий хотя бы один такой метод, тоже будет абстрактным. Объект такого класса создать нельзя (в некоторых языках допускается, но вызов абстрактного метода приведёт к ошибке). Наследники абстрактного класса должны предоставить реализацию для всех его абстрактных методов, иначе они, в свою очередь, будут абстрактными классами.

Для каждого класса, имеющего хотя бы один виртуальный метод, создаётся таблица виртуальных методов. Каждый объект хранит указатель на таблицу своего класса. Для вызова виртуального метода используется такой механизм: из объекта берётся указатель на соответствующую таблицу виртуальных методов, а из неё, по фиксированному смещению, — указатель на реализацию метода, используемого для данного класса. При использовании множественного наследования или интерфейсов ситуация несколько усложняется за счёт того, что таблица виртуальных методов становится нелинейной.

Краткая справка по C++

Алфавит - Aa...Zz 0...9 _ -основные символы, из которых могут состоять имена, имена не могут начинаться с цифры. Любой оператор завершается символом ; Комментарии отделяются символами //комментарий до конца строки или /* комментарий */

Переменные нужно определять явно до использования конструкцией вида <модификаторы> <тип> <имя переменной>[,<имя переменной 2>,<имя переменной 3>]; Модификаторы относятся к типу переменной.

В С++ нет различия между функциями и процедурами. Функции определяются конструкцией вида <тип возвращаемого значения> <модификаторы> <имя функции>([<параметры функции>]){ <код функции> }

Если функция не должна ничего возвращать, то вместо <тип возвращаемого значения> ставиться void . Модификаторы позволяют сделать функцию макросом, изменить способ передачи параметров, а также обеспечить экспорт и импорт функции из dll. Функцию можно предварительно объявить, поместив её прототип до её фактического объявления или в .h файл. Прототип функции имеет вид <тип возвращаемого значения> <модификаторы> <имя функции>([<параметры функции>]); .

Функция вызывается конструкцией вида <имя функции>(<параметр1>,<параметр2>); , при этом можно явно использовать эту конструкцию в операторе  присваивания или в другой функции, например int a=sin(10); или ShowMessage(FloatToStr(sin(b))); .

Блок представляет из себя часть кода , заключённого в фигурные скобки ( {  } ).

Оператор присваивания в C++ - знак = , а оператор проверки равенства - знак == .

В операторах ветвления, циклов и т.п. заключение в фигурные скобки одиночного оператора необязательно, т.е. if(a==b){b=c;} абсолютно эквивалентно if(a==b)b=c; .К телу функции это не относится, его нужно обязательно заключать в фигурные скобки!

Основные операторы в C++ это: = , == , if(<условие>){<код>}[else {<код>}] , while(<условие>){<код>} , for(<обнуление переменной>;<условие>;<увеличение переменной>){<код>} , do{<код>} while(<условие>); , &<переменная> , *<указатель> , (<тип>)<переменная или выражение> .

& - ссылка на переменную. Функции сами по себе являются указателями. Понятия ссылка и указатель одно и тоже. * - операция разименования, позволяет обратится к объекту по ссылке на него, т.е. a=*(&a) .

Операция (<тип>)  - это приведение типов, позволяет на объект одного типа ссылаться как на объект другого типа.

Если перед именем переменной при её объявлении поставить * , то это будет указатель. int *x=&a; При приведении типов указателей нужно после типа ставить *. int *x=(char*)d;

Основные типы данных : int - 4байтное число со знаком,  char -1байтное целое со знаком, символ , float - вещественное , double - вещественное двойной точности.

Основные модификаторы : unsigned , signed , long , short . Часто используются без типа, считается, что тип - int , т.е. unsigned int и просто unsigned - одно и тоже. unsigned - беззнаковость, signed - со знаком, применительно к int и char не имеет смысла, long - длинный, применительно к int не имеет смысла, к char не применяется, увеличивает в двое точность double , short - короткий, к char не применяется, делает int 2байтовым. Пример  - unsigned int a=10; unsigned *b; unsigned x=-88;-ошибка, присваивать беззнаковой переменной отрицательные числа нельзя!

Оператор return <выражение>; завершает работу функции , которая возвращает значение указанного выражения или переменной.

Пример:int a=10;//определяем переменную
int f(int value);//прототип функции
int* p=&a,x=a+1;
x=x+f((*p)-1);//вызываем функцию
int f(int value)//сама функция
{
if(value<10/*условие*/) return value+1;
else return value;}



Случайные файлы

Файл
47726.rtf
55204.rtf
60429.rtf
2094-1.rtf
139134.rtf




Чтобы не видеть здесь видео-рекламу достаточно стать зарегистрированным пользователем.
Чтобы не видеть никакую рекламу на сайте, нужно стать VIP-пользователем.
Это можно сделать совершенно бесплатно. Читайте подробности тут.