Два вопроса dynamic_cast - PullRequest
       22

Два вопроса dynamic_cast

2 голосов
/ 15 июня 2011
  1. Будете ли вы использовать динамическое приведение в методе частых прогонов?У него большие накладные расходы?

  2. Что именно представляет собой указатель, возвращаемый dynamic_cast.Указатель на тот же адрес?указатель на другой экземпляр?Мне не хватает этого понимания.Более конкретно: есть назначение, которое я хочу сделать для указателя типа отца, только если во время выполнения он оказывается указателем на тип сына.Решения?

Спасибо.

Ответы [ 5 ]

6 голосов
/ 15 июня 2011

dynamic_cast помогает проверить достоверность при выполнении downcasting.

Возвращает значение NULL или выдает исключение (std::bad_cast для ссылок), если указатель или ссылка не могут быть безопасно понижены.

Вы бы использовали динамическое приведение вчасто используемый метод?У него большие накладные расходы? dynamic_cast использует некоторые дополнительные RTTI(Run Time Type Information) для определения достоверности приведения.Так что накладные расходы наверняка.Как правило, указатель на typeinfo из type будет добавлен к virtual table.Обычно я говорю, потому что сам виртуальный механизм зависит от реализации компилятора (может отличаться для разных компиляторов).

Вам придется профилировать свой код с помощью некоторых хороших инструментов профилирования, чтобы определить, многократно ли вызов dynamic_cast снижает производительность вашего кода.

Что именно является указателемвозвращается dynamic_cast.Указатель на тот же адрес?указатель на другой экземпляр?

Это легче понять, когда вместо анализа downcasting с dynamic_cast мы анализируем upcasting .Для типа base и другого типа derived, который наследуется от base, тип derived будет содержать подобъект типа base.Когда указатель на объект derived преобразуется в указатель на base, результатом операции будет адрес субобъекта base внутри derived.Выполнение dynamic_cast отменяет эту операцию и возвращает указатель на объект derived, который содержит подобъект base в адресе, переданном в качестве аргумента (static_cast делает то же самое, но применяет возможное смещение без фактической проверки типа среды выполнения).

В простейшем случае при одиночном (не виртуальном) наследовании подобъект derived будет выровнен base, но в случае множественного наследования,это не будет иметь место:

struct base {
   int x;
   virtual void foo() {}
};
struct another_base {
   virtual void bar() {}
};
struct derived : base, another_base {};
int main() {
   derived d;
   base * b = &d;           // points to the base subobject inside derived
   another_base * o = &d;   // points to the another_base subobject inside derived

   std::cout << std::boolalpha
       << ( static_cast<void*>(b) == dynamic_cast<derived*>(b) ) << "\n"
       << ( static_cast<void*>(o) == dynamic_cast<derived*>(o) ) << std::endl;
}

Программа напечатает true, false.Обратите внимание, что вам нужно явно привести один из указателей к void*, если вы хотите сравнить их, иначе компилятор выполнит неявное повышение значения указателя downcasted .

1 голос
/ 15 июня 2011

Вы бы использовали динамическое приведение в методе часто запуска? У него большие накладные расходы?

У него не очень большие накладные расходы. Но это зависит от реализации RTTI компилятором. Однако не оптимизируйте преждевременно.

Что именно является указателем, возвращаемым dynamic_cast. Указатель на тот же адрес? указатель на другой экземпляр? Мне не хватает этого понимания. Более конкретно: есть назначение, которое я хочу сделать для указателя типа отца, только если во время выполнения он оказывается указателем на тип сына. Решения?

Любой объект производного класса содержит объекты своих базовых классов. dynamic_cast возвращает указатель на один из этих объектов (обычно это один и тот же указатель, когда класс наследует только один базовый класс, но это не тот же указатель, если класс наследует более 1 базового класса). Но это зависит от используемого компилятора.

1 голос
/ 15 июня 2011

Неважно, если метод «часто запускается», только если он работает, имеет важное отрицательное влияние на требуемую производительность.и единственный способ выяснить это - профилировать ваш код.

Возвращенный указатель - это просто указатель.Вам нужно опубликовать пример кода, чтобы уточнить вторую половину вашего вопроса.Если вы имеете в виду это:

Base * p1 = ....;

Derived * d = dynamic_cast<Derived*>(p1);
if ( d ) {
     (*d) = "foobar";
}

Тогда это нормально, если Derived поддерживает назначение.

0 голосов
/ 15 июня 2011

Что именно является указателем, возвращаемым dynamic_cast.Указатель на тот же адрес?указатель на другой экземпляр?Мне не хватает этого понимания.Более конкретно - есть назначение, которое я хотел бы сделать для указателя типа отца, только если во время выполнения он оказывается указателем на тип сына.1006 *

dynamic_cast вернет ненулевой указатель, если указанный объект является экземпляром целевого класса или класса, производного от целевого класса.Он возвращает нулевой указатель, если объект, на который указывает указатель, не является экземпляром целевого класса.

ПРИМЕЧАНИЕ.так же.Пример: Предположим, что ChildA наследуется от двух классов, Base и SomeInterface.Вы можете static_cast указатель ChildA на указатель Base и указатель SomeInterface.По крайней мере, один из этих двух указателей родительского класса не будет указывать на ту же область памяти, что и указатель ChildA.Динамическое приведение любого из этих двух указателей родительского класса вернет исходный указатель ChildA.

0 голосов
/ 15 июня 2011
  1. См. Принятый ответ для этого поста Как профилировать мое приложение C ++ на linux . Он описывает, с какими опциями вызывать valgrind, и приложение для просмотра профиля приводит к приятному графическому интерфейсу.

  2. Динамическое приведение вернет указатель того типа, который вы произвели, с тем же адресом, что и аргумент, поэтому он указывает на тот же объект. При динамическом приведении типа «сын» к «типу отца» динамическое приведение вызовет исключение std :: bad_cast, если аргумент не относится к типу «сын».

...