virtuales usar punteros puntero poo herencia funciones funcion estructuras ejemplo dev con como codigo c++ virtual member-function-pointers

usar - punteros c++



Punteros a funciones miembro virtuales. ¿Como funciona? (3)

Considere el siguiente código C ++:

class A { public: virtual void f()=0; }; int main() { void (A::*f)()=&A::f; }

Si tuviera que adivinar, diría que & A :: f en este contexto significaría "la dirección de la implementación de A de f ()", ya que no hay una separación explícita entre los punteros a las funciones de miembro regular y las funciones de miembro virtual. . Y como A no implementa f (), eso sería un error de compilación. Sin embargo, no lo es.

Y no solo 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 llamará B :: f.

¿Cómo sucede?


Aquí hay demasiada información sobre los punteros de función de miembros. Hay algunas cosas sobre las funciones virtuales en "Los compiladores de buen comportamiento", aunque IIRC cuando leí el artículo que estaba hojeando esa parte, ya que el artículo es en realidad sobre 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 a la función miembro se implemente como una estructura que contiene un puntero a una función "thunk" que realiza la llamada virtual.


Funciona porque el Estándar dice que así es como debería suceder. Hice algunas pruebas con GCC, y resulta que para funciones virtuales, GCC almacena el desplazamiento de la tabla virtual de la función en cuestión, 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; }

Ese programa genera 1 5 : las compensaciones de bytes de las entradas de la tabla virtual de esas dos funciones. Sigue el Itanium C ++ ABI , que especifica eso .


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

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