#c #c 11 #casting
#c #c 11 #Кастинг
Вопрос:
Предположим, у меня есть базовый класс и 2 классифицированных производных от него. Все производные классы имеют свою собственную логику, несовместимую между ними. Тестовое приложение выглядит следующим образом:
#include <iostream>
#include <vector>
class Base
{
public:
Base(int x) { m_x = x; }
virtual int getResult() { return m_x; }
protected:
int m_x;
};
class DerivedA : public Base
{
public:
DerivedA(int x) : Base(x) {}
int getResult() override { return m_x * 2; }
};
class DerivedB : public Base
{
public:
DerivedB(int x) : Base(x) {}
int getResult() override { return m_x * m_x; }
};
int main()
{
std::vector<Base *> objects;
objects.push_back(new DerivedA(1));
objects.push_back(new DerivedB(2));
objects.push_back(new DerivedA(3));
objects.push_back(new DerivedB(4));
for(Base *object: objects)
{
DerivedA *obj = static_cast<DerivedA *>(object);
if(obj != nullptr)
{
std::cout << obj->getResult() << std::endl;
}
}
return 0;
}
Я ожидаю получить только 2 результата, т.Е. Что Только экземпляры типа DerivedA
могут быть приведены к DerivedA
, но не DerivedB
. Но, к моему удивлению, это не так. static_cast
выполняет приведение DerivedB
к DerivedA
без проблем. Почему это происходит? Я могу понять это, если бы я привел к Base
, но не к этому. В то же время dynamic_cast
работает так, как ожидалось, т.Е. Приведение DerivedB
к DerivedA
сбою.
Комментарии:
1.
static_cast
предполагается, что программист поступает правильно. Когда вы этого не сделаете, разыменование результирующего указателя будет иметь неопределенное поведение.2. В этом как раз и заключается разница между двумя типами приведений.
dynamic_cast
проверяет преобразование во время выполнения и завершается ошибкой, если типы не совпадают.static_cast
проверяет типы во время компиляции и завершает работу успешно (т. Е. компилирует), если не может определить, что они не могут совпадать.3. Радость неопределенного поведения заключается в том, что вещи в основном могут работать, что затрудняет поиск возможного сбоя
4. Я всегда предполагал, что
reinterpret_cast
это зависит от программиста, ноstatic_cast
выполняет проверку во время компиляции.5. @folibis: Он действительно выполняет приведение во время компиляции, но поведение по-прежнему не определено.
Ответ №1:
Поведение при разыменовании указателя, являющегося результатом преобразования a static_cast
из a DerivedB*
в a DerivedA*
, не определено. Это строгое нарушение псевдонимов.
Комментарии:
1. Приведение к несвязанному типу — это просто UB. Строгое наложение псевдонимов имеет важное значение, когда приведение работало бы в противном случае.