Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.15.190.144] |
|
Страницы: (4) « Первая ... 2 3 [4] все ( Перейти к последнему сообщению ) |
Сообщ.
#46
,
|
|
|
Ну собственно я про это и написал. Как ещё проверить находится ли один узел в поддереве другого. Единственный эффективный способ спуститься по дереву иерархии от наследника к предку. Мы либо наткнёмся на переданный класс и выполним приведение, либо дойдём до конца иерархии, так и не встретив переданного класса, и вернём ноль, в знак того, что приведение невозможно. Это при одиночном наследовании.
Можно развернуть цикл спуска в точке приведения, проверка будет быстрее. Кроме того, так можно прервать проверки до достижения самого корневого класса (переданный в dynamic_cast указатель сам может быть производным, и его базовые классы проверять незачем). При множественном наследовании при скольжении по дереву возможно несколько продолжений. Однако только одно может вести к классу передаваемого указателя. В этом случае развёртывание цикла даёт даже больший эффект, так как не приходится перебирать варианты продолжений. |
Сообщ.
#47
,
|
|
|
По-моему, вы упускаете из виду такой вариант, или я вас не так понял:
class IInterface1 { /* ... */ }; class IInterface2 { /* ... */ }; class MyClass: public IInterface1, public IInterface2 { /* ... */ }; void foo(IInterface1* pInt1) { /* ... */ IInterface2 pInt2 = dynamic_cast<IInterface2*>(pInt1); if (pInt2 != 0) /* ... */ } P.S. Говоря об обходе графа, я не преувеличивал. |
Сообщ.
#48
,
|
|
|
Цитата Qraizer @ Вот тут согласен. В этом случае выглядит практически нереальным во время компиляции угадать цепочку приведения. Значит остаётся только бродить по графу разыскивая нужный маршрут. И это достаточно медленный процесс, особенно в случае неудачи. Перекрёстное приведение – часто встречающаяся фича. |
Сообщ.
#49
,
|
|
|
Цитата Qraizer @ По-моему, вы упускаете из виду такой вариант, или я вас не так понял: Я лишь хотел уточнить, что несмотря на обобщенное название темы, автора (в первую очередь) интересует конкретная простая ситуация, когда за номинальным базовым типом ObjectBase* скрывается реальный объект типа XObject*, к которому и нужно выполнить dynamic_cast (см.#1 и пояснение в #8). Поэтому прежде чем разглагольствовать на общие темы (на 4 страницах), следовало бы пояснить, что в данном конкретном случае dynamic_cast выполняется максимально быстро (за одно сравнение typeid реального типа с требуемым). |
Сообщ.
#50
,
|
|
|
Цитата leo @ Я лишь хотел уточнить, что несмотря на обобщенное название темы, автора (в первую очередь) интересует конкретная простая ситуация, когда за номинальным базовым типом ObjectBase* скрывается реальный объект типа XObject*, к которому и нужно выполнить dynamic_cast (см.#1 Да, действительно, меня интересовала конкретика. Но ради понимания общего механизма, на будущее, все остальные объяснения, тоже были интересны. |
Сообщ.
#51
,
|
|
|
Цитата leo @ Сравнений может быть и больше. Приведение нормально выполняется ещё и в случаях, когда реальный тип оказывается наследником требуемого. А это можно выяснить только пробежав по всей цепочке наследования от реального типа к требуемому. за одно сравнение typeid реального типа с требуемым |
Сообщ.
#52
,
|
|
|
Цитата amk @ Приведение нормально выполняется ещё и в случаях, когда реальный тип оказывается наследником требуемого. Это уже обобщение. Я говорю о конкретном случае (см.#1 и #8), когда dynamic_cust выполняется не "от балды", а только после предварительной проверки типа объекта по уникальному идентификатору типа Category (или по тому же tipeid). Если автор обобщит задачу и будет присваивать одно значение Category двум и более наследуемым классам, то да - проверка будет выполняться по цепочке "от реального типа к требуемому". А пока у него реальный тип = требуемому, проверка при dynamic_cust выполняется за одно сравнение. |
Сообщ.
#53
,
|
|
|
Цитата leo @ Если автор обобщит задачу и будет присваивать одно значение Category двум и более наследуемым классам, то да - проверка будет выполняться по цепочке "от реального типа к требуемому". А пока у него реальный тип = требуемому, проверка при dynamic_cust выполняется за одно сравнение. У меня category выставляется полуавтоматически. Собственно я завёл её как раз ради такой или подобной идентификации. Например, чтобы из списка разных объектов, быстро выбрать объекты нужных категорий. Но в некоторых местах, получилось весело и неоднозначно. У меня есть ромбовидная иерархия... ] class ObjectBase abstract {} class XObject: public virtual ObjectBase {}; class YObject: public virtual ObjectBase {}; class XYObject final: public XObject, public YObject { }; Причём объекты нужны и могут быть типов XObject, YObject или XYobject. В первом сообщении, я спрашивал лишь про один фрагмент. Но оно действительно для всех классов. Несколько функций работают только с XObject или YObject. Понятно и допустимо, что они будут работать с XYObject. Но моя первоначальная функция приведения, точнее проверки категорий, ломались на таком. Пришлось делать идентификаторы из битовых флагов. enum class ObjectCategory { XObject = 0x0011, YObject = 0x0012, XYObject = 0x0013 }; Ну и проверка, соответственно уже проверяла маску, а не полное равенство. Ох и морока же. Была мысль заюзать std::bitset или switch. Но остановился на битовых флагах. И да в предыдущем варианте тестирования, кроме приведение типа объекта, к его реальному типу, делалось соответственно приведение к одному из базовых типов. Если реальный объект XYObject, а нужен только XObject, указатель же вообще ObjectBase... Но даже в этом случае, всё отрабатывало быстро и чётко. Как я понимаю, сначала dynamic_cast смотрел VMT и обнаружив там XYObject, спускался вниз по иерархии, проверяя либо XObject либо YObject. |
Сообщ.
#54
,
|
|
|
Дружище, на сколько я понял, был главный вопрос этот:
Можно "копья ломать" еще стопицот страниц. Домыслы, догадки. Но решение в каких-то числах, пусть в шкальных оценках, ИМХО, тебе дадут тесты. Сделай пару-тройку синтетических примеров с разветвленным множественным наследованием, замерь на таймере высокого разрешения - и ты получишь, как минимум, порядок в разности скоростей. Чесслово, рассуждений выше для тестов - выше крыши. А вот численный результат, уверен, был бы любопытен всем |
Сообщ.
#55
,
|
|
|
Цитата JoeUser @ Но решение в каких-то числах, пусть в шкальных оценках, ИМХО, тебе дадут тесты. Пытался замерять такты, через clock(). там значения плавали, для одного и того же кода. При этом два диапазона значений, для двух разных кодов, были довольно близкими. Я не смог однозначно сказать, что какой-то код быстрее. Субъективно же чуточку ускорилось. Следовало сразу мерить профайлером, в более суровых и чистых условиях, а теперь поздняк метаться. На данный момент у меня нет действющих dynamic_cast. |
Сообщ.
#56
,
|
|
|
Цитата Eric-S @ Я не смог однозначно сказать, что какой-то код быстрее. Субъективно же чуточку ускорилось. На большлом компе проверял? проверь на железке с памятью 2М, и скоростью машины времен начала 90-х, хотя бы.Либо каждый замен времени умножай на 100 или 1000, и сравни есть ли разница, это че совсем точно,но лучше чем никак. |
Сообщ.
#57
,
|
|
|
Цитата settler @ Лучше повторять тест. Подобрать такое количество повторов, чтобы вместе они занимали 1-10 секунд. Тогда по крайней мере паре-тройке цифр в результате можно будет доверять.Либо каждый замен времени умножай на 100 или 1000, Цитата Eric-S @ Значит можно считать, что притормаживание несущественно. В любом случае основное время у тебя занимает обработка после проверки, и на фоне этого времени небольшое притормаживание dynamic_cast будет незаметно. там значения плавали, для одного и того же кода. При этом два диапазона значений, для двух разных кодов, были довольно близкими. Я не смог однозначно сказать, что какой-то код быстрее. |