Программирование >>  Полиморфизм без виртуальных функций в с++ 

1 ... 57 58 59 [ 60 ] 61 62 63 ... 144


Альтернативная возможность - написание кода непосредственно на С или С++, поэтому эффективности уделялось особое внимание. Предпочтение было отдано замкнутым класса.м, а не иерархиям и встраиванию критических по времени операций. Кроме того, классы проектировались так, чтобы их можно было при.менять в традиционно написанных программах без крупных переделок или дополнительного обучения программистов. В частности, не делалось никаких попыток предоставить пользователю возможность модифицировать поведение этих классов с по.мощью замещения виртуальных функций в производных классах. Если бы пользователю понадобился общий модифицируемый класс, его .можно было бы написать, взяв стандартный в качестве основы. Напри.мер:

class String { простой к эффективный . . .

class My string { обцкй к адаптируемый

String rep;

... public:

. . .

virtual void append(const Strings); virtual void append(const My string&); . . .

8.3.1. Библиотека потокового ввода/вывода

Се.мейство функций printf из библиотеки С - эффективный и во .многих случаях удобный механизм ввода/вывода. Однако эти функции не обеспечивают контроля типов и не допускают применения определенных пользователем типов (классов и перечислений). Поэтому я начал ду.мать о безопасной, лаконичной, расширяемой и эффективной альтернативе printf. Отчасти вдохновение снизошло на .меня, когда я прочел последние полторы страницы Ada Rationale* ( Обоснование языка Ada ) [Ichbiah, 1979], где доказывается, что нельзя построить лаконичную и безопасную библиотеку ввода/вывода без специальной поддержки со стороны языка. Я воспринял этот категоричный тезис как вызов. В результате появилась библиотека потокового ввода/вывода, впервые реализованная в 1984 г. и описанная в работе [Stroustrup, 1985]. Вскоре после этого Дейв Пресот-то (Dave Presotto) иерениса.л ее с целью улучшить эффективность за счет отказа от использования стандартных функций ввода/вывода из библиотеки С. Вместо этого ои напрямую обращался к средствам операциошюй системы. Работа была сделана без изменения интерфейсов потока.

Для знакомства с повой ко1ще11цией потокового ввода/вывода рассматривался такой пример:

fprintf(stderr, х = %s\n ,x);

Поскольку f print f () не проверяет переданных аргу.ментов, основываясь иа предположении, что они соответствуют форматной строке, это небезопасно. Обратимся к работе [Stroustrup, 1985], где в связи с эти.м говорится:



Если бы X принадлежало определенному пользователем типу, например complex, то нельзя было бы задать формот вывода х ток же спокойно, кок для типов, о которых printf знает (к примеру, %s и %d). Для вывода комплексного число прогроммисту пришлось бы писать последовательность вызовов функций, например:

fprintf(stderr, X = ); put complex(stderr,x); fprintf(stderr, \n );

Это неизящно. A уж в С++-программе, где применяется много определенных пользователем типов, токая запись было бы совсем неудобной.

Безопасного использовония типов и единооброзия можно достичь с помощью одного перегруженного имени для семейства функций вывода. Например:

put(stderr, X = ); put(stderr,х); put(stderr, \n );

Тип аргумента определяет, какая именно функция put будет вызвоно. Одноко и это слишком многословно. В С++ для решения задачи используется поток выводо, для которого оператор << имеет смысл вывести в :

сегг X = X \п ;

где сегг - стандартный поток вывода для ошибок (эквивалентный stderr из С). Если х имеет тип int и ровно 123, то результат этого вывода будет таким:

X = 123

и в конце - символ новой строки.

Данный способ можно использовать, если только х принадлежит типу, для которого определен оператор , а определить такой оператор в новом типе просто. Ток, если х имеет определенный пользователем тип complex и ровно (1, 2 . 4), то это предложение выведет в сегг строку

X = (1,2.4)

Такой потоковый ввод/вывод реолизовон с помощью средств языка, доступных любому программисту. Кок в С, ток и в С++ нет встроенных в язык средств вводо/выводо. Потоковый ввод/вывод включен в библиотеку .

Возможность использования вместо именованной функции оператор вывода первоначально предложил Дуг Макилрой по аналогии с операторами перенаправления ввода/вывода в командных интерпретаторах UNIX (>, , I и т.д.). Требуется только, чтобы оператор возвращал свой левый операнд для передачи последующим операторам:

Функция aperator возвращает ссылку но объект ostream, для которого оно вызыволось, с тем чтобы можно было применить к ней следующий объект ostream. Например, предложение

сегг X = х; где X имеет тип int, интерпретируется кок

(cerr.operator ( x = ) ) . operator (х) ;



в частности отсюдо следует, что при печоти в одном предложении нескольких элементов они будут выведены в ожидоемом порядке: слево нопрово .

Если бы я решил использовать обычную именованную функцию, то пользователю пришлось бы писать код, как в последнем примере. Для реализации ввода и вывода рассматривалось несколько операторов:

Оперотор присвоивония подошел бы и для вводо, и для выводе, но нос не устроивоет свой-авенноя ему оссоциотивность. То еть cout=a=b интерпретироволось бы кок cout= (a=b). Кроме того, большинство пользовотелей предпочло бы, чтобы оперотор ввода отличолся от опероторо выводе.

Россмотриволись и опероторы < и >, но сементико меньше чем и больше чем ток прочно укоренилось в сознонии, что предложения вводо/выводо с их использовонием были бы про-ао нечитаемы (видимо, для << и >> дело обстоит не ток). Помимо этого, символ < респоло-жен не той же клевише, что и , , поэтому многие писоли бы выражения вроде

cout < X , у , z;

Провильно диагностировать токую ошибку было бы нелегко .

Надо сказать, что сегодня мы уже могли бы перегрузить нужной семантикой оператор занятая (см. раздел 11.5.5), но в C-I-+ образца 1984 г. это было невоз.можно.

В и.менах стандартных потоков cout, cin и т.д. буква с означает character (символ). Эти потоки проектировались для ввода/вывода символов.

Для версии 2.0 Джерри Шварц переписал и частично перепроектировал потоковую библиотеку, чтобы она была полезна большему числу приложений и обеспечивала более высокую эффективность файлового ввода/вывода [Schwarz, 1989]. Значительного улучшения удалось добиться благодаря выдвинутой Эндрю Кени-гом [Koenig, 1991] идее манипуляторов для управления такими деталями форматирования, как задание точности для вывода чисел с плаваюшей точкой и основания системы счисления для целых. Например:

int i = 1234;

cout i по умолчанию десятичная: 1234

hex i шестнадцатеричная: 4d2

<< oct i \n; восьмеричная: 2322

Опыт, приобретенный при работе с потока.ми, явился основной причиной для изменения базовой системы типов и правил перегрузки. Цель - позволить, чтобы значения типа char трактовались как символы, а не короткие целые числа, как это было в С (см. раздел 11.2.1). Например, в результате выполнения

char ch = b; cout a ch;

в версии 1.0 была бы выведена строка цифр, представляюших значения кодов символов а и Ь, тогда как в версии 2.0 выводится ab, как и ожидалось.

Библиотека iostreams, поставлявшаяся с версией Cfront 2.0, стала .моделью для реализаций других поставшиков и того варианта iostream, который включат в бу-дуцщй стандарт.



1 ... 57 58 59 [ 60 ] 61 62 63 ... 144

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика