|
Программирование >> Оптимизация возвращаемого значения
Данные класса В Указатель т виргуальныи GiTMBUH класс Данные класса С vptr Указатель на вир1уальный базовый класс le класса D Данные класса А vptr Рис. 4.7 На рисунке закрашены части объекта, которые добавляются компилятором. Отношение закрашенных и пустых областей определяется объемом данных в классе. Для маленьких классов дополнительные расходы будут относительно велики. Для классов с большим объемом данных затраты окажутся менее значительными, хотя и достаточно заметными. Странность этой схемы в том, что хотя она включает четыре класса, на ней изображены только три указателя виртуальных таблиц. Различные реализации могут создавать и четыре указателя виртуальных таблиц, но достаточно всего трех (оказывается, объекты В и D могут совместно использовать один указатель), и большинство реализаций с помощью этого добивается снижения накладных расходов, привносимых компилятором. Итак, вы увидели, что применение виртуальных функций делает объекты больше и мешает использованию встроенных функций, и убедились, что множественное наследование и виртуальные базовые классы также могут увеличивать размер объектов. Обратимся теперь к последней теме, затратам на идентификацию типов во время выполнения программы (runtime type identification, сокращенно RTTI). только в общих чертах иллюстрирует то, как использование виртуальных базовых классов может приводить к появлению скрытых указателей на объекты. В некоторых реализациях добавляется меньшее число указателей, а в некоторых они не добавляются вообще (в таком сл5ае указатели виртуальных таблиц и виртуальной таблицы несут двойную нагрузку). Если объединить этот рисунок с предыдущим, на котором было показано, как к объектам добавляются указатели виртуальной таблицы, станет ясно, что если базовый класс А в иерархии, приведенной на станице 130, имеет виртуальные функции, то объект типа D будет устроен примерно следующим образом (см. рис. 4.7). С1 vtbl typejnfo класса С1 реализация С1::-С1 - - реализация C1::f1 -реализация C1::f2 --ь. реализация С1 ::f3 Рис. 4.8 При такой реализации память будет тратиться только на добавление еще одной ячейки в каждую виртуальную таблицу и выделение места для хранения одного объекта type inf о для каждого класса. Так же как потери памяти на создание виртуальных таблиц вряд ли будут заметны в большинстве приложений, так же маловероятно, что возникнут проблемы из-за размера объектов type inf о. В табл. 4.1 приведены сведения о затратах, сопровождающих использование виртуальных функций, множественного наследования, виртуальных базовых классов и идентификации типов. Некоторые, увидев эту таблицу, могут ужаснуться и заявить: Я продолжаю писать на С! . Но помните, что каждое из описанных свойств обеспечивает какие-то функции, которые иначе придется программировать вручную. В большинстве случаев самостоятельная реализация оказывается менее эффективной и надежной, чем код, созданный компилятором. Например, эмуляция вызовов виртуальных функций с помощью вложенных операторов switch или каскадирование операторов if-then-else дает больше кода, чем вызовы виртуальных функций, и этот код к тому же медленнее выполняется. Более того, вам придется отслеживать типы Идентификация типов во время выполнения программы позволяет получать информацию об объектах и классах. При этом для хранения запрашиваемой информации нужно отвести определенное место. Информация содержится в объекте типа type inf о, доступ к которому в классе можно пол5ить при помоши оператора typeid. По логике в каждом классе должна быть только одна копия данных RTTI, и должен сушествовать способ пол5ения такой информации для каждого объекта. В действительности это не совсем так. В спецификации языка сказано, что гарантируется получение точных сведений о динамическом типе объекта, только если этот тип содержит хотя бы одну виртуальную функцию. Данные RTTI выполняют примерно ту же задачу, что и таблица виртуальных функций. Вам нужна только одна копия информации для каждого класса, и нужно иметь способ получения соответствующей информации из любого объекта, содержащего виртуальную функцию. Параллель между RTTI и таблицами виртуальных функций не случайна: RTTI была разработана для ее реализации с помощью виртуальной таблицы класса. Например, индекс О в массиве виртуальной таблицы может содержать указатель на объект type inf о соответствующего таблице класса. Виртуальная таблица класса С1 со стр. 125 имела бы тогда вид, представленный на рис. 4.8.
объектов Bpjnyro, из-за чего объекты будут также содержать метки типов; поэтому зачастую вы не пол5ите никакого выигрыша даже от меньшего размера объектов. Важно понимать, к каким затратам приводит использование виртуальных функций, множественного наследования, виртуальных базовых классов и RTTI, но также важно понимать, что если вам нужна функциональность этих свойств, то вы должны так или иначе заплатить за нее. Иногда существуют разумные причины для обхода предоставляемых компиляторами возможностей. Например, скрытые указатели виртуальных таблиц и указатели на виртуальные базовые классы могут усложнить сохранение объектов С++ в базе данных или их передачу между процессами, поэтому стоит эмулировать эти свойства, чтобы было легче выполнять подобные задачи. Но с точки зрения эффективности, запрограммировав свойства самостоятельно, вы вряд ли выиграете по сравнению с их реализацией при помощи компилятора.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |