Пока указатель на базовый тип фактически указывает на экземпляр производного типа, такое использование не является неопределенным в соответствии со стандартом C++. Однако в вашем примере кода указатель b
не указывает на экземпляр B
или любого из его производных типов (которых нет), он указывает на экземпляр из A
. Таким образом, ваш код действительно вызывает неопределенное поведение.
Я нашел ответ на SO, в котором говорится, что это может привести к UB, тестируя его, он скомпилировался и работал правильно.
Тот факт, что некоторый код компилируется и работает правильно, не исключает возможности кода, вызывающего неопределенное поведение, потому что неопределенное поведение включает в себя «кажется, что работает». Причина, по которой вам следует избегать неопределенного поведения, заключается в том, что нет никакой гарантии, что оно будет работать таким же образом при следующем вызове UB.
Это неопределенное поведение? Если да, то каким будет правильный подход к этой проблеме?
В вашем образце да, это неопределенное поведение. Правильный подход будет зависеть от того, что на самом деле должен делать ваш код, поскольку приведенный вами пример в лучшем случае является академическим примером.
Чтобы было понятно, следующая модификация вашей функции main()
имеет четко определенное поведение и явно разрешена стандартом C++:
B objectB;
A* ptrA = &objectB;
B* b = static_cast<B*>(ptrA);
b->Show();
Здесь он хорошо определен, потому что указатель ptrA
на самом деле указывает на экземпляр B
, хотя сам указатель имеет тип A*
. В приведенном выше примере будет работать приведение от A*
к B*
, а затем вызов одной из функций B
для приведенного указателя. Разница в том, что в примере в вашем вопросе b
фактически не указывает на экземпляр B
.
Соответствующий пункт (выделено мной):
Стандарт С++ 5.2.9/8 Статическое приведение [expr.static.cast]
Rvalue типа «указатель на cv1 B
», где B
— тип класса, можно преобразовать в rvalue типа «указатель на cv2 D
», где D
— это класс, производный (пункт 10) от B
, если существует допустимое стандартное преобразование из «указателя на D
» в «указатель на B
» (4.10), cv2 то же самое cv-квалификация или более cv-квалификация, чем cv1, и B
не является виртуальным базовым классом D
. Значение нулевого указателя (4.10) преобразуется в значение нулевого указателя целевого типа. Если rvalue типа «указатель на cv1 B
» указывает на B
, который на самом деле является подобъектом объекта типа D
, результирующий указатель указывает на объемлющий объект типа D
. В противном случае результат приведения не определен.
person
In silico
schedule
16.02.2013