Вызов методов производного класса из указателя на базовый класс через переинтерпретацию указателя на метод. Это УБ?

С указателем на объект производного типа, назначенным указателю его базового класса, я обнаружил, что вы можете переинтерпретировать_приведение метода из производного класса к указателю базового класса, даже если базовый класс не имеет любую такую ​​функцию (виртуальную, скрытую или иную). И его можно разыменовать и вызвать оттуда, и он «просто работает». Но я хотел бы убедиться, что это не UB. Это УБ? Это портативно?

Компилируемый пример:

#include <cstdio>

struct A { /* no foo method */ };
struct B : public A { void foo(void){printf("foo");} };

typedef void (B::*B_FOO_PTR)( void );
typedef void (A::*A_FOO_PTR)( void );

int main ( void ) {
    B b;
    A* a = &b;

    // address of a and b are identical

    B_FOO_PTR b_ptr = &B::foo;
    // (a->*b_ptr)(); // COMPILE ERROR: calling B method from A. Not Allowed, but...

    A_FOO_PTR a_ptr = reinterpret_cast<A_FOO_PTR>(b_ptr);
    (a->*a_ptr)(); // works, outputs "foo"

    return 0;
}

person Brandon    schedule 08.07.2019    source источник
comment
Да, это неопределенное поведение.   -  person 0x499602D2    schedule 09.07.2019


Ответы (1)


Это неопределенное поведение. Единственными преобразованиями функций указателя на член, при которых вы можете вызвать результат, являются:

  • конвертация туда-обратно и
  • указатель-на-элемент-базы к указателю-на-член-производного.

Вы пытаетесь выполнить обратную вторую точку, которая исключена из этого списка.

person M.M    schedule 08.07.2019
comment
А для второго пункта нужно использовать стандартное преобразование (например, вообще без приведения или через static_cast), а не reinterpret_cast. - person aschepler; 09.07.2019