Перво-наперво: вы должны использовать static_cast
. reinterpret_cast
не очень подходит для этого.
Но чтобы приведение в действие сработало, ваша программа должна знать, куда она движется. Под этим я подразумеваю, что он должен знать путь, который должен пройти, чтобы разыграть от A
до B
. Если A
и B
находятся в одной иерархии классов, это просто: просто следуйте указанной иерархии классов, чтобы выполнить приведение.
Но если у вас есть:
struct C: A, B {};
И это единственное отношение между A
и B
, static_cast
не может узнать о C
(это та информация, которую предоставляет RTTI), и, следовательно, он не может выполнять приведение, поскольку A
и B
на самом деле не связаны.
Чтобы указать этот путь, вы должны разрешить своей программе как-то это узнать. Самый простой способ - использовать шаблон wrapper
:
template<typename T>
class wrapper {
managed_object* ptr;
public:
template<typename Trait> Trait* object() const {
return static_cast<Trait*>(static_cast<T*>(ptr));
}
};
Тогда:
MyType a;
wrapper<MyType> w{&a};
trait1* asTrait1 = w.object<trait1>(); // OK
Обратите внимание, что я точно говорю, как выполнять приведение, сначала понижая до производного типа, а затем "возвращая обратно" к признаку.
Примечание о reinterpret_cast
Если вы преобразуете класс в его Base (MyType
в trait1
), dynamic_cast
вернет указатель или ссылку на подобъект базового класса в производном объекте (static_cast
также может сделать это преобразование правильно). Это означает, что значение возвращаемого указателя может фактически отличаться от значения предоставленного указателя. reinterpret_cast
никогда не внесет такое изменение в значение указателя. Он будет просто переосмысливать то, что ему передано, как новый тип, что явно неверно. Очевидный вывод - не использовать reinterpret_cast
для выполнения приведения в иерархиях классов.