Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
141-150.doc
Скачиваний:
15
Добавлен:
27.09.2019
Размер:
97.79 Кб
Скачать

Int I; // целая переменная

const int ci = 1; // целая константа

Int * pi; // указатель на целую переменную

const int * pci; // указатель на целую константу

int * const ср = &i; // указатель-константа на целую переменную

const int * const срс = &ci; // указатель-константа на целую константу

145) Указатель на функцию

Указатель на функцию содержит адрес в сегменте кода, по которому располагается исполняемый код функции, то есть адрес, по которому передается управление при вызове функции. Указатели на функции используются для косвенного вызова функции (не через ее имя, а через обращение к переменной, хранящей ее адрес), а также для передачи имени функции в другую функцию в качестве параметра. Указатель функции имеет тип «указатель функции, возвращающей значение заданного типа и имеющей аргументы заданного типа»:

тип (*имя) ( список_типов_аргументов );

Например, объявление:

int (*fun) (double, double);

задает указатель с именем fun на функцию, возвращающую значение типа int и имеющую два аргумента типа double.

146) Понятие структуры расширено в С++ так, что появилась возможность вводить закрытые (private) и открытые (public) члены. Это касается как членов данных, так и функций-членов структуры.

К открытым членам структуры имеется непосредственный доступ из лю-бой функции, имеющей доступ к объекту структуры.

К закрытым членам имеют доступ не все функции, а только те, чьи полномочия включают право доступа к этим членам. Таковыми являются функции-члены структур.

Полезно рассматривать закрытую часть, как код, доступный только разработчику, а открытую часть – как описание интерфейса, который используется клиентами. Разработчик может изменить закрытую часть, и это не повлияет на правильность использования структуры клиентом. То есть при изменении закрытой части структуры не нужно переписывать код, который использует эту структуру (хотя может потребоваться его перекомпиляция).

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

Другое преимущество – локализация ошибок. Неправильное значение закрытого члена данных может быть вызвано только неверным кодом функций-членов.

Классы являются формой структуры, у которой право доступа по умолчанию закрытое. Таким образом, struct и class взаимозаменяемы при условии надлежащего определения прав доступа.

147) C++ предоставляет набор классов файловых потоков, с помощью которых можно очень легко выполнять операции ввода и вывода (В/В) с файлами.

  • Используя выходной файловый поток, вы можете писать информацию в файл с помощью оператора вставки (<<).

  • Используя входной файловый поток, вы можете читать хранимую в файле информацию с помощью оператора извлечения (>>).

  • Для открытия и закрытия файла вы используете методы файловых классов.

  • Для чтения и записи файловых данных вы можете использовать операторы вставки и извлечения, а также некоторые методы файловых классов.

148) Чтобы, например, указать ширину полей, левое или правое выравнивание и т.д. можно использовать printf(), а можно сделать то же самое при помощи средств форматирования ввода/вывода языка С++. Существуют два способа форматирования ввода/вывода.

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

enum { skipws = 0x0001,

left = 0x0002,

right = 0x0004,

internal = 0x0008,

dec = 0x0010,

oct = 0x0020,

hex = 0x0040,

showbase = 0x0080,

showpoint = 0x0100,

uppercase = 0x0200,

showpos = 0x0400,

scientific = 0x0800,

fixed = 0x1000,

unitbuf = 0x2000,

stdio = 0x4000

};

Рассмотрим что делают перечисленные выше флаги.

Флаг Описание

skipws - Следующие в начале символы-разделители (пробелы, символы табуляции и новой строки) при выполнении ввода отбрасываются.

left -Осуществляется ввод с левым выравниванием

right Осуществляется ввод с правым выравниванием (по умолчанию)

internal -Знак или префикс системы счисления выравнивает слева, число выравнивает справа

dec- Численные значения выводятся в десятичной форме (по умолчанию)

oct -Численные значения выводятся в восьмеричной форме

hex -Численные значения выводятся в шестнадцатиричной форме

showbase - Позволяет при выводе указывать числовую базу (десятичную, восьмеричную, шестнадцатиричную)

showpoint - Приводит к выводу десятичной запятой и нулей справа для всех чисел с плавающей запятой вне зависимости, нужно это или нет

uppercase - При выводе чисел с плавающей точкой при использовании экспоненциальной формы выводится большая буква E. Также при выводе чисел в шестнадцатиричной форме символ 'x' выводится в верхнем регистре.

showpos - Приводит к тому, что перед положительным числом будет выводится знак "+"

scientific - Числа с плавающей запятой выводятся с использованием научной нотации

fixed - Числа с плавающей запятой выводятся в нормальной нотации

unitbuf - При каждой операции вставки вывода данные немедленно заносится в поток

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

Первая функция, которую мы рассмотрим, - это функция setf(), используемая для установки флагов

long setf(long flags);

Функция принимает в качестве параметра рассмотренные выше флаг или флаги, соединенные между собой при помощи побитового ИЛИ. Она возвращает предыдущее значение флага. Рассмотрим пример:

cout.setf(ios::hex);

cout.setf(ios::showpos);

cout<<123<<" "<<123.45<<"\n";

cout<<67<<" "<<678.9<<"\n";

выведет на экран

7b +123.45

43 +678.9

тоже самое будет на экране после выполнения следующего кода

cout.setf(ios::hex | ios::showpos);

cout<<123<<" "<<123.45<<"\n";

cout<<67<<" "<<678.9<<"\n";

Для отключения установленных флагов нужно использовать функцию unsetf(). Она имеет следующий прототип:

long unsetf(long flags);

Функция возвращает значение предыдущей установки флага и сбрасывает флаги, определяемые параметром flags. Пример:

cout.setf(ios::showpos | ios::hex);

cout<<123<<" "<<123.45<<"\n";

cout.unsetf(ios::showpos | ios::hex);

cout<<123<<" "<<123.45<<"\n";

выведет на экран

7b +123.45

123 123.45

Кроме флага форматирования также можно установить ширину поля потока, символ для заполнения и число цифр после десятичной запятой. Для этого используются следующие функции:

int width(int len);

char fill(char ch);

int precision(int num);

Функция width() устанавливает ширину поля и возвращает текущую ширину. Вторая функция - fill() устанавливает текущий символ заполнения и возвращает предыдущий символ заполнения. По умолчанию используется пробел. А функция precision устанавливает точность чисел с плавающей точкой. В научном режиме эта функция определяет количество цифр после десятичной запятой. В обычной нотации функция обозначает количество выводимых цифр. Точность, установленная по умолчанию, равна 6. Функция width() воздействует только на один вывод информации, а после этого в действие вступают параметры принятые по умолчанию. В случае с остальными двумя функциями новые установки остаются действовать до их явного обновления. Приведем пример:

cout.width(10);

cout.fill('*');

cout<<123<<"\n";

cout.width(10);

cout<<456<<"\n\n";

cout<<"Using precision\n";

float price1 = 20.405f;

float price2 = (float)1.9+8.0/9.0;

cout<<price1<<"\n"<<price2<<"\n\n";

cout.precision(2);

cout<<price1<<"\n"<<price2<<"\n\n";

cout.setf(ios::scientific);

cout<<price1<<"\n"<<price2<<"\n\n";

выведет на экран

*******123

*******456

Using precision

20.405

2.78889

20

2.8

2.04e+001

2.79e+000

А теперь мы переходим к рассмотрению второго способа форматирования ввода/вывода. Второй способ - это использование манипуляторов.

Манипуляторы являются специальными функциями, которые позволяют изменять флаги потока. Существуют манипуляторы с параметрами и без. Если Вы используете манипуляторы с параметрами, подключите файл iomanip.h

Рассмотрим манипуляторы без параметров:

ends - помещает в выходной поток нулевой символ;

endl помещает в выходной поток символ конца строки и вызывает метод flush;

flush выгружает буфер потока;

dec, hex, oct устанавливают основания 10, 16 и 8 соответственно;

ws заставляет игнорировать ведущие пробелы при вводе.

Манипуляторы с параметрами

setbase(int b) задает основание системы счисления;

resetiosflags(long f) сбрасывает флаги, указанные в параметре;

setiosflags(long f) устанавливает флаги, указанные в параметре;

setfill(int ch) задает заполняющий символ;

setprecision(int n) задает точность вещественных чисел;

setw(int n) задает ширину поля.

Использование манипуляторов рассмотрим на примере

cout<<setw(5)<<setfill('*')<<22<<endl;

cout<<hex<<11<<endl;

выведет на экран

***22

b

149) Функторы в C++ являются сокращением от "функциональные объекты". Функциональный объект является экземпляром класса С++, в котором определён operator(). Если вы определите operator() для C++ класса, то вы получите объект, который действует как функция, но может также хранить состояние. Например,

#include <iostream>

#include <string>

class SimpleFunctor {

std::string name_;

public:

SimpleFunctor(const char *name) : name_(name) {}

void operator()() { std::cout << "Oh, hello, " << name_ << endl; }

};

int main() {

SimpleFunctor sf("catonmat");

sf(); // выводит "Oh, hello, catonmat" }

Обратите внимание, что мы можем вызывать sf() в функции main, хотя sf является объектом. Это потому, что в классе SimpleFunctor для него определён operator().

Чаще всего функторы в С++ используются в качестве предикатов, псевдозамыканий или функций сравнения в алгоритмах STL. Вот вам ещё один пример. Предположим, у вас есть список целых чисел и вы хотите найти сумму всех четных и сумму всех нечетных. Идеальная задача для функтора и for_each.

#include <algorithm>

#include <iostream>

#include <list>

class EvenOddFunctor {

int even_;

int odd_;

public:

EvenOddFunctor() : even_(0), odd_(0) {}

void operator()(int x) {

if (x%2 == 0) even_ += x;

else odd_ += x;

}

int even_sum() const { return even_; }

int odd_sum() const { return odd_; }

};

int main() {

EvenOddFunctor evenodd;

int my_list[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

evenodd = std::for_each(my_list, my_list+sizeof(my_list)/sizeof(my_list[0]), evenodd);

std::cout << "Сумма чётных: " << evenodd.even_sum() << "\n";

std::cout << "Сумма нечётных: " << evenodd.odd_sum() << std::endl;

// вывод:

// Сумма чётных: 30

// Сумма нечётных: 25

}

Здесь экземпляр EvenOddFunctor передается в for_each. for_each итерируется по каждому элементу в my_list и вызывает функтор. После этого он возвращает копию функтора evenodd, который содержит сумму чётных и нечётных элементов.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]