|
Программирование >> Полиморфизм без виртуальных функций в с++
вызов этого конструктора. Стало быть, конструктор должен выполнить и выделение памяти, и ее инициализацию. При таком подходе, если единица трансляции выделяет память для всех объектов класса X с помощью new и не вызывает встраиваемых функций из X, то ее не надо перекомпилировать в случае из.менения размера или представления X. Единица трансляции - это принятый в ANSI С термин для обозначения исходного файла после обработки препроцессором. Иными слова.ми, это то, что передается компилятору. Такой подход показался очень удобным для уменьшения числа компиляций моих моделирующих программ. Однако в сообществе пользователей С with Classes и С+н- важность данной оптимизации была осознана много позже (см. раздел 13.2). Оператор delete был введен как парный к new, точно так же как функция free () является парной по отношению к malloc () - см. разделы 3.9 и 10.7. 2.11.3. Функции call и return Интересно, что в первой реализации С with Classes была возможность, которая в С++ исчезла, хотя меня часто просят ее вернуть. Можно было определить функцию, которая неявно вызывалась при каждом вызове любой функции-члена (кроме конструктора), и другую функцию, которая вызывалась перед каждым возврато.м из любой функции-члена (кроме деструктора). Эти функции назывались соответственно call и return. Я использовал их для синхронизации в классе монитора, входившего в первоначальный вариант библиотеки для поддержки многозадачности [Stroustrup, 1980b]: class monitor : object { /* ... */ call О; { /* установить защелку */ } return О; { /* снять защелку */ } /* ... */ Данные функции аналогичны методам : before и : after в языке CLOS. Они были исключены из языка, поскольку никто (кроме меня) ими не пользовался и мне так и не удалось убедить публику, что у них имеются важные применения. В 1987 г. Майк Тиман (Mike Tiemann) предложил альтернативное решение [Tiemann, 1987], которое назвал обертками (wrappers), но на семинаре разработчиков USENIX в Эстес Парк было решено, что с этой идеей связано слишком много проблем, и включать ее в С++ не стали. 2.12. Менее сущеавенные средства в С with Classes были включены две не очень важные особенности: перефузка оператора присваивания и аргументы по умолчанию. Они были предтечами механизма перегрузки в С++ (см. раздел 3.6). 2.12.1. Перегрузка оператора присваивания Вскоре было отмечено, что классы с нефивиальным представлением, такие как string и vector, нельзя нормально копировать, поскольку принятая в С се.мантика копирования (побитовое) для таких типов не годилась. Для них копирование по умолчанию сводилось к разделяемому несколькими объектами представлению, а не к созданию настоящих копий. В качестве решения я позволил программисту самому определять семантику копирования [Stroustrup, 1980]: К сожолению, стандартное почленное (кок для struct) присвоивоние не всегда идеально. Типичный объект кпоссо - это только корень информационного дерева, о копирование одного корня без учета ветвей нежелательно. Точно так же простая перезапись объекта классо может привести к хаосу. Решение этих проблем - в изменении семантики присвоивония для объектов классо. Это можно сделоть, объявив функцию-член клоссо operator=. Нопример: class X { public: int а; class у * р; void operator= (class x *); void x.operator= (class x * from) { a = from->a; delete p; p = from->p; from->p = 0; Токим образом, для объектов классо х мы определили разрушающее чтение, а не оперо-цию копирования, подразумеваемую стондартной семантикой . В работе [Stroustrup, 1982] приведен вариант примера, в котором проверяется условие this= = from, чтобы корректно обработать присваивание самому себе. Как видите, я учился этой технике на собственных ошибках. Если в классе был определен оператор присваивания, то он использовался для всех операций копирования. Во время инициализации объект сначала инициировался значением по умолчанию с помощью функции new (конструктора) без аргументов, а потом выполнялось присваивание. Это было сочтено неэффективным и привело к появлению в С++ копирующих конструкторов (см. раздел 11.4.1). 2.12.2. Аргументы по умолчанию Интенсивное использование конструкторов по умолчанию - результат наличия операторов присваивания, определенных пользователем, - привело к появлению аргументов по умолчанию [Stroustrup, 1980]: Список аргументов по умолчанию добавлен к механизму классов уже на очень поздней стадии, чтобы противостоять распространению практики передочи идентичных списков стандартных аргументов для объектов клосса через оргументы функции, аргументов для объектов класса, являющихся членоми другого класса, о токже аргументов для базового клосса. Предоставление в токих случоях списка аргументов показалось достаточно разумным, чтобы побороть антипатию к включению еще одного средство . Они позволяли сделать объявление class более кратким и похожим но объявление struct*. Что не реализовано в С with Classes Вот пример: Можно объявить список аргументов по умолчанию для функции new {). Зотем этот список будет использоваться всякий роз, кок объект класса создается без укозония аргументов. Так, при ноличии объявления class char stack { void new(int=512); объявление class char stack s3; допустимо, при этом s3 инициолизируется вызовом s3 . new ( 512) . При наличии общего .механизма перегрузки функци!! (см. раздел 3.6 и главу 11) аргументы по умолчанию становятся логически избыточными и в лучшем случае обеспечивают небольшое удобство нотации. Однако списки аргументов по умолчанию существовали в С with Classes много лет, прежде чем в С++ появилась перегрузка. 2.13. Что не реализовано в С with Classes Ряд возможностей!, которые позднее были включены в С++ или обсуждаются до сих пор, рассматривались уже во время работы над С with Classes. Среди них -виртуальные функции, статические члены, шаблоны и множественное наследование. Однако у всех этих обобщений есть свои области применения, но для проектирования, реализации, документирования и обучения каждой особенности языка требуются время, силы и опыт... Концепция базового класса - это инженерный компромисс, как и вообще концепция класса в С [Stroustrup, 1982b] . Я специально упомянул, что приобретение опыта было необходимым. На этом разговор о вреде включения избыточных возможностей и о пользе прагматического подхода можно считать исчерпанным. Возможность включения автоматического сборщика мусора несколько раз рассматривалась и до 1985 г., но была признана неподходящей для языка, который использовался в системах реального времени, и для программирования низкоуровневых системных задач, вроде написания драйверов агшаратпых устройств. В те дни сборщики мусора были не такими совершенными, как сейчас, а нынешние мощности процессоров и объем памяти просто несравнимы с прежни.ми. Личный опыт работы с Simula и отчеты о других системах, где имеется сборка мусора, убедили меня, что эта технология неприемлема в системах, которые разрабатывали я и мои коллеги. Если бы в определении С with Classes (и даже С++) требовалось наличие автоматической сборки мусора, то язык был бы более изящным, но мертворожденным . Обсуждалась и прямая поддержка параллельности, но я отказался от этой идеи в пользу библиотечной реализации (см. раздел 2.1).
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |