|
Программирование >> Полиморфизм без виртуальных функций в с++
При реализации схемы сборки мусора следует реии1ть, нужно ли вызывать деструктор для объекта, попавшего в мусор. В [2nd я писал; Сборку мусора можно россмотривоть кок моделирование бесконечной памяти в ограниченном объеме. Имея это в виду, мы можем ответить но вопрос: Должен ли сборщик мусора вызывать деструктор для кождого попавшего.в мусор объекта? Ответ - нет, ток кок объект просто помещен в свободную помять, о не удален и не уничтожен. Если оценивать ситуоцикз под этим углом, то delete - это не более чем требование вызвать деструктор (вместе с извещением системы о том, что память объекта можно использовать повторно). Но что, если мы действительно хотим выполнить некоторое действие над объектом, распределенным в свободной памяти, но ток и не удаленным? Донноя проблема не косоется объектов в статической и овтомотической памяти; для них деструкторы всегда вызываются неявно. Еще отметим, что действия, выполняемые во время сборки мусора , могут осуществляться в любое время, ночиноя с момента последнего использовония объекта и до зовершения роботы программы. Значит, но момент выполнения этих действий неизвестно состояние программы. Если же такого рода действия все же необходимы, то проблему их выполнения в неопределенный момент уничтожения можно решить с помощью сервера регистрации. Когда объекту нужно произвести какие-то действия в конце программы, он помещает свой адрес и указатель но функцию очистки в некоторый глобальный ассоциативный массив . Описанная модель, конечно, работоспособна, но, быть может, вызов деструкторов сборщиком мусора все же удастся сделать достаточно простым. Это зависит от того, какие объекты попадают в .мусор и какие действия выполняют деструкторы. К сожалению, данная проблема из числа тех, для которых трудно поставить реальный эксперимент, да и в других языках похожего опыта, кажется, нет. Итак, я не думаю, что создать приемлемый для С++ .механизм сборки мусора просто, но это не невозможно. А если учесть, сколько людей думают над дайной проблемой, то наверняка скоро появится несколько решений. Глава 11. Перегрузка Дьявол прячется в деталях. Анонимный автор 11.1. Введение Операторы призваны обеспечить удобство нотации. Рассмотрим формулу F=M* А (сила = масса * ускорение). В учебниках по элементарной физике эта формула не записывается в виде assign (F,multiply (М, А) ) . Если переменные могут иметь разные типы, то нужно определить, разрешать ли смешанную арифметику или требовать явного приведения операндов к обшему типу. Например, если М имеет тип int, а А - тип double, то мы можем либо принять запись М*А и считать, что М нужно перед умножением привести к типу double, либо потребовать от программиста писать нечто вроде double (М) *А. Для С++, как для С, Fortran и почти всех языков, применяемых для вычислений, выбран первый подход. И это чревато определенными осложнениями. С одной стороны, пользователи хотят естественных преобразований без протестов компилятора, с другой - некорректные преобразования могут привести к сбою в работе программы. Если добавить сюда требование совместимости с довольно хаотичной системой встроенных типов и преобразований С, то становится понятно, что проблема действительно трудна. Стремление к гибкости и свободе выражения противоречит стремлению к безопасности, предсказуемости и простоте. В этой главе рассматривается, к каким усовершенствованиям механизмов перегрузки привел данный конфликт. 11.2. Разрешение перегрузки Перегрузка имен функций и операторов в том виде, в каком она первоначально появилась в С++ (см. раздел 3.6), [Stroustrup, 1984b], завоевала популярность, но выявились и присушие механизму проблемы. В [Stroustrup, 1989b] так резюмированы улучшения, введенные в версию 2.0: Механизм перегрузки в С++ был пересмотрен. Цель - обеспечить разрешение типов, которые раньше считались слишком похожими , и добиться независимости от порядка объявлений. Получившаяся в результате схема более выразительно и позволяет выявить больше ошибок неоднозначности . Некоторые предпочли бы F=MA, на объяснение тога, как такая нотация могла бы работать (перегрузка отсутствующего пробела), выходит за рамки этой книги. Благодаря более детальному механизму разрешения появилась возможность перегружать имена, принимая во внимание различия между int и char, float и double, const и не-const, а также различия между базовым и производным классами. Независимость от порядка позволила избавиться от ряда ошибок. Ниже все аспекты перегрузки рассматриваются по очереди, также объясняется, почему ключевое слово overload больше не употребляется. 11.2.1. Детальное разрешение в первоначальном варианте правила перегрузки в С++ учитывали ограничения, присушие встроенным типам С [Kernighan, 1978]: не было значений типа float (точнее, rvalue такого типа), поскольку при вычислениях тип float сразу же расширялся до double. Аналогично не было и значений типа char, так как при каждом использовании char происходило расширение до int. Отсюда недовольство пользователей, вызванное невоз.можностью естественным образом создать библиотеку для вычислений с плавающей точкой одинарной точности, а также жалобы на то, что при работе с функциями, манипулирующими символами, легко сделать ошибки, которых можно было бы избежать. Рассмотрим функцию вывода. Если мы не можем перегрузить ее на основе различия между int и char, приходится заводить два и.мени. В первоначальном варианте потоковой библиотеки (см. раздел 8.3.1.) были такие функции: ostreamb operator (int); вывод int (включая преобразованные char) в виде последовательности цифр ostreamb put(char с); вывод char в виде символов Однако многие писали так: cout X ; и, естественно, удивлялись, почему выводится 88 (числовое значение ASCII X), а не обычный символ X. Для решения проблемы правила типов в С++ были изменены таким образом, что типы char и float не подвергались расширению в механизме перегрузки. Помимо этого тип символьного литерала, например, X был определен как char. В то же время была принята появившаяся незадолго до этого в ANSI С нотация для записи литералов типа unsigned и float. Поэтому стала возможной следующая запись: float abs(float); double abs(double); int abs(int); unsigned abs(unsigned); char abs(char); void f() { abs(l); abs(int) abs(lU); abs(unsigned) abs(l.O); abs(double)
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |