Pregunta

Considere el siguiente código de C ++:

class A
{
public:
      virtual void f()=0;
};


int main()
{
     void (A::*f)()=&A::f;
}

Si yo tendría que adivinar, diría que y A :: f en este contexto significaría "la dirección de la ejecución de f () de A", ya que no hay separación explícita entre los punteros a funciones regulares y miembros funciones miembro virtuales. Y ya que A no implementa f (), que sería un error de compilación. Sin embargo, no lo es.

Y no sólo eso. El siguiente código:

void (A::*f)()=&A::f;
A *a=new B;            // B is a subclass of A, which implements f()
(a->*f)();

en realidad llamada B :: f.

¿Cómo es posible?

¿Fue útil?

Solución

Aquí es demasiada información acerca de los punteros de función miembro. Hay algunas cosas acerca de las funciones virtuales en "Los compiladores de buen comportamiento", aunque IIRC cuando leí el artículo que estaba Skimming esa parte, ya que el artículo es realmente acerca de la implementación de delegados en C ++.

http://www.codeproject.com/KB/cpp/FastDelegate.aspx

La respuesta corta es que depende del compilador, pero una posibilidad es que el puntero de función miembro se implementa como una estructura que contiene un puntero a un "thunk" función que hace la llamada virtual.

Otros consejos

Funciona porque la norma dice que es como debe suceder. Hice algunas pruebas con GCC, y resulta que para las funciones virtuales, tiendas CCG el desplazamiento de la función en cuestión tabla virtual, en bytes.

struct A { virtual void f() { } virtual void g() { } }; 
int main() { 
  union insp { 
    void (A::*pf)();
    ptrdiff_t pd[2]; 
  }; 
  insp p[] = { { &A::f }, { &A::g } }; 
  std::cout << p[0].pd[0] << " "
            << p[1].pd[0] << std::endl;
}

Eso productos de los programas 1 5 - los desplazamientos de bytes de las entradas de la tabla virtuales de esas dos funciones. De ello se desprende la Itanium C ++ ABI , que especifica que .

No estoy del todo seguro, pero creo que es un comportamiento polimórfico solo regular. Creo que en realidad significa &A::f la dirección del puntero de función en la vtable de la clase, y es por eso que no está recibiendo un error de compilación. El espacio en la viable todavía asignado, y que es el lugar en realidad se está recibiendo de vuelta.

Esto tiene sentido porque las clases derivadas esencialmente sobrescriben estos valores con punteros a sus funciones. Esta es la razón por (a->*f)() trabaja en su segundo ejemplo -. f se hace referencia a la viable que se implementa en la clase derivada

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top