Что конкретно может пойти не так, при использовании reinterpret_cast для преобразования от базы к потомку?
Рассмотрим следующий код:
class A {/*...*/};
class B : public A {/*...*/};
void func(A*const a)
{
B*const b = reinterpret_cast<B*const>(a);
b->do_something();
}
В одном крупном проекте было найдено несколько подобных мест. Я знаю, что это приводит к неопределенному поведению.
Меня интересуют конкретно следующие вопросы:
- Если указатель
aвсегда указывает на объект типаB, то будут ли у нас проблемы? - Если указатель
aуказывает не на объект типаB, то что?
Ответы (2 шт):
Автор решения: Harry
→ Ссылка
- В этом случае проблем не должно быть (особенно если использовать
B*b=(B*)a), но как вы это сможете гарантировать?... Чтобы это гарантировать, следует использоватьdynamic_castс проверкой результата. - Будет задница. Мягко говоря. UB.
P.S. от меня лично - мне ужасно не нравится приведение предка к потомку. У меня убежденность, что это говорит о плохом проекте - грубо говоря, когда, чтоб машина поехала, к ней что-то привязывают скотчем :)
P.P.S. Немного о dynamic_cast - хотя ваш вопрос не о нем, так что если это лишнее - извините..
Автор решения: user7860670
→ Ссылка
- Почти наверняка будут. Например когда указатель на
Aполучен неявным приведением илиstatic_castуказателя наB, но эти классы не обладают свойством pointer interchangeable, или когда он получен посредствомreinterpret_cast, но объекты имеют разные выравнивания.
#include <iostream>
class A { int x; };
class B : public A
{
public: virtual void do_something() { std::cout << "test"; }
};
void func(A*const p_a)
{
// При reinterpret_cast адрес в указателе не меняется.
B*const p_b = reinterpret_cast<B*>(p_a);
// Адрес у указателе неверный, обращение к vtable наверняка приведет к падению.
::std::cout << "B *" << static_cast<void *>(p_b) <<std::endl;
p_b->do_something();
}
int main()
{
B b{};
B * p_b{&b};
::std::cout << "B *" << static_cast<void *>(p_b) <<std::endl;
// Адрес подобъекта A отличается от адреса B, из-за наличия vtable.
A * p_a{p_b};
::std::cout << "A *" << static_cast<void *>(p_a) <<std::endl;
func(p_a);
return 0;
}
- Конечно будут: помимо всего вышеперечисленного еще и нарушение strict aliasing.