|
Программирование >> Поддержка объектно-ориентированного программирования
Конструктор Omanip int хранит свои аргументы в i и f, а с помощью operator вызывается f() с параметром i. Часто объекты таких классов называют объект-функция. Чтобы результат строки cout << setprecision(4) << angle был таким, как мы хотели, необходимо чтобы обращение setprecision(4) создавало безымянный объект класса Omanip int, содержащий значение 4 и указатель на функцию, которая устанавливает в потоке ostream значение переменной, задающей точность вещественных: ostream& set precision(ostream&,int); Omanip int setprecision(int i) return Omanip int(& set precision,i); Учитывая сделанные определения, operator () приведет к вызову precision(i). Утомительно определять классы наподобие Omanip int для всех типов аргументов, поэтому определим шаблон типа: template<class T> class OMANIP { T i; ostream& (*f) (ostream&,T); public: OMANIP(ostream (*ff) (ostream&,T), T ii) : f(ff), { } friend ostream& operator<<(ostream& os, OMANIP& m) { return m.f(os,m.i) } С помощью OMANIP пример с установкой точности можно сократить так: ostream& precision(ostream& os,int) os.precision(i); return os; OMANIP<int> setprecision(int i) return OMANIP<int>(&precision,i); В файле <iomanip.h> можно найти шаблон типа OMANIP, его двойник для istream - шаблон типа SMANIP, а SMANIP - двойник для ioss. Некоторые из стандартных манипуляторов, предлагаемых поточной библиотекой, описаны ниже. Отметим,что программист может определить новые необходимые ему манипуляторы, не затрагивая определений istream, ostream, OMANIP или SMANIP. Идею манипуляторов предложил А. Кениг. Его вдохновили процедуры разметки (layout ) системы ввода-вывода Алгола68. Такая техника имеет много интересных приложений помимо ввода-вывода. Суть ее в том, что создается объект, который можно передавать куда угодно и который используется как функция. Передача объекта является более гибким решением, поскольку детали выполнения частично определяются создателем объекта, а частично тем, кто к нему обращается. 10.4.2.1 Стандартные манипуляторы ввода-вывода Это следующие манипуляторы: Simple manipulators: ios& oct(ios&); в восьмеричной записи ios& dec(ios&); в десятичной записи ios& hex(ios&); в шестнадцатеричной записи ostream& endl(ostream&); добавить \n и вывести ostream& ends(ostream&); добавить \0 и вывести ostream& flush(ostream&); выдать поток istream& ws(istream&); удалить обобщенные пробелы Манипуляторы имеют параметры: SMANIP<int> setbase(int b); SMANIP<int> setfill(int f); SMANIP<int> setprecision(int p); SMANIP<int> setw(int w); SMANIP<long> resetiosflags(long b); SMANIP<long> setiosflags(long b); Например, cout << 1234 << << hex << 1234 << << oct << 1234 << endl; напечатает 1234 4d2 2322 cout << setw(4) << setfill(#) << ( << 12 << )\n ; cout << ( << 12 << )\n ; напечатает (##12) (12) Не забудьте включить файл <iomanip.h>, если используете манипуляторы с параметрами. 10.4.3 Члены ostream В классе ostream есть лишь несколько функций для управления выводом, большая часть таких функций находится в классе ios. class ostream : public virtual ios { ... public: ostream& flush(); ostream& seekp(streampos); ostream& seekp(streamoff, seek dir); streampos tellp(); ... Как мы уже говорили, функция flush() опустошает буфер в выходной поток. Остальные функции используются для позиционирования в ostream при записи. Окончание на букву p указывает, что именно позиция используется при выдаче символов в заданный поток. Конечно эти функции имеют смысл, только если поток присоединен к чему-либо, что допускает позиционирование, например файл. Тип streampos представляет позицию символа в файле, а тип streamoff представляет смещение относительно позиции, заданной seek dir. Все они определены в классе ios: class ios { ... enum seek dir { beg=0, от начала файла cur=1, от текущей позиции в файле end=2 от конца файла поместит # в file[10]. 10.4.4 Члены istream Как и для ostream, большинство функций форматирования и управления вводом находится не в классе iostream, а в базовом классе ios. class istream : public virtual ios { ... public: int peek() istream& putback(char c); istream& seekg(streampos); istream& seekg(streamoff, seek dir); streampos tellg(); ... Функции позиционирования работают как и их двойники из ostream. Окончание на букву g показывает, что именно позиция используется при вводе символов из заданного потока. Буквы p и g нужны, поскольку мы можем создать производный класс iostreams из классов ostream и istream, и в нем необходимо следить за позициями ввода и вывода. С помощью функции peek() программа может узнать следующий символ, подлежащий вводу, не затрагивая результата последующего чтения. С помощью функции putback(), как показано в $$10.3.3, можно вернуть ненужный символ назад в поток, чтобы он был прочитан в другое время. 10.5 Файлы и потоки Ниже приведена программа копирования одного файла в другой. Имена файлов берутся из командной строки программы: #include <fstream.h> #include <libc.h> void error(char* s, char* s2 = ) cerr << s << << s2 << \n; exit(1); int main(int argc, char* argv[]) if (argc != 3) error( wrong number of arguments ); ifstream from(argv[1]); if (!from) error( cannot open input file ,argv[1]); ostream to(argv[2]); if (!to) error( cannot open output file ,argv[2]); char ch; while (from.get(ch)) to.put(ch); ... Позиции в потоке отсчитываются от 0, как если бы файл был массивом из n символов: char file[n-1]; и если fout присоединено к file, то fout.seek(10); fout<<#;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |