С++ всегда ли reinterpret_cast возвращает результат?

У меня есть два класса, A и B. A является родительским классом B, и у меня есть функция, которая принимает указатель на класс типа A, проверяет, относится ли он также к типу B, и если да, то вызывает другую функция, которая принимает указатель на класс типа B. Когда функция вызывает другую функцию, я передаю reinterpret_cast(a) в качестве параметра. Если это кажется неоднозначным, вот пример кода:

void abc(A * a) {
  if (a->IsA("B")) { //please dont worry much about this line,
                     //my real concern is the reinterpret_cast
    def(reinterpret_cast<B *>(a));
  };
};

Итак, теперь, когда вы знаете, как я вызываю «def», мне интересно, действительно ли reinterpret_cast возвращает указатель типа B, который будет отправлен в качестве параметра для def. Буду признателен за любую помощь. Спасибо


person mike bayko    schedule 11.07.2017    source источник
comment
Вы получите B*, но это все равно очень плохо. Скорее всего, это не тот указатель, который вы ожидаете. Вместо этого вы должны сделать static_cast   -  person Justin    schedule 11.07.2017
comment
Я изменю его на static_cast, спасибо.   -  person mike bayko    schedule 11.07.2017
comment
или объединить тест и приведение в dynamic_cast   -  person pm100    schedule 11.07.2017
comment
Спасибо, это тоже хорошая идея.   -  person mike bayko    schedule 11.07.2017


Ответы (5)


У вас будет указатель типа B*, но reinterpret_cast не очень хорош.

Если вы уверены, что это тип B, используйте static_cast, если нет, используйте dynamic_cast и проверьте указатель (если dynamic_cast не работает, возвращается nullptr)

См. https://stackoverflow.com/a/332086/5303336.

person Random Coder 99    schedule 11.07.2017
comment
Этот ответ был бы улучшен, если бы вы могли уточнить, почему reinterpret_cast не очень хорош. - person François Andrieux; 11.07.2017
comment
Я добавил ссылку на ответ, рассказывающий, почему это не здорово и как правильно использовать разные приведения. - person Random Coder 99; 11.07.2017

reinterpret_cast всегда будет делать то, что вы говорите — это кувалда. Ты можешь сделать

def(reinterpret_cast<B *>(42));

or

std::string hw = "hello";
def(reinterpret_cast<B *>(hw));

он всегда будет возвращать указатель, который может указывать на правильный тип. Предполагается, что вы знаете, что делаете

person pm100    schedule 11.07.2017

reinterpret_cast является результатом сломанной системы типов. Его поведение предполагает, что существует объединение, такое как

 union { 
     TypeA anA;
     TypeB aB;
 } a;

so

 reinterpret_cast< B* >( a );

Предполагается, что a является указателем на элемент anA, и затем может доставить адрес aB.

Если тип является частью той же иерархии классов, то static_cast‹> позволит вам узнать во время компиляции, достаточно ли информации для выполнения приведения. Обычно это происходит, когда B является базовым классом A (по отдельности или умножается).

Если для работы static_cast недостаточно информации, то можно заставить работать dynamic_cast‹>. Это тот случай, когда тип B каким-то образом является производным от A.

Важно отметить, что dynamic_cast<B*>( a ) или static_cast< B*>( a ) могут не дать один и тот же адрес при успешном выполнении.

Это связано с тем, что при множественном наследовании вторичное наследование создает в объекте несколько классов и виртуальных таблиц. Когда это происходит, static_cast, dynamic_cast корректируют базовый адрес объекта, чтобы найти правильный базовый адрес встроенного класса.

Тот факт, что dynamic_cast и static_cast могут изменить адрес, является причиной того, что reinterpret_cast не рекомендуется. Это может привести к значению, которое не делает то, что вы хотите.

person mksteve    schedule 12.07.2017

Reinterpret cast всегда будет возвращать указатель. Это может быть просто недопустимый указатель в том смысле, что он фактически указывает на объект типа B.

Если B имеет более одного базового класса, а A не является первым базовым классом, приведение переинтерпретации сделает неправильную вещь и не сможет выполнить необходимую корректировку указателя.

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

person PaulR    schedule 11.07.2017

Как заявляли другие, reinterpret_cast - неправильное решение, вместо этого используйте dynamic_cast:

void abc(A * a) {
    B *b = dynamic_cast<B*>(a);
    if (b) {
        def(b);
    }
}
person Remy Lebeau    schedule 12.07.2017