EDITAR: me he dado cuenta que todavía estoy recibiendo votos en este mes más tarde, a pesar de que mi respuesta original es mala y engañosa (Ni siquiera puedo recordar lo que estaba pensando en ese momento, y se ¡no tiene mucho sentido!), así que pensé en intentar aclarar la situación, ya que las personas todavía deben llegar aquí a través de la búsqueda.
En la situación más normal, se puede casi pensar en
struct A { int i; int foo() { return i; } };
A a; a.foo();
como
struct A { int i; };
int A_foo(A* this) { return this->i; };
A a; A_foo(&a);
(empezando a parecerse a C
, ¿verdad?) Así que se podría pensar el puntero &A::foo
simplemente haría ser lo mismo que un puntero de función normal. Pero hay un par de complicaciones: herencia múltiple y funciones virtuales.
Así que imaginemos que tenemos:
struct A {int a;};
struct B {int b;};
struct C : A, B {int c;};
Podría ser presentado como esto:

Como se puede ver, si se quiere apuntar al objeto con una A*
o a C*
, apunte al inicio, pero si quiere apuntarlo con B*
, tiene que apuntar a algún punto intermedio.Entonces, si C
hereda alguna función de miembro de B
y desea apuntar a ella, luego llame a la función en un C*
, necesita saber cómo barajar el puntero this
. Esa información necesita ser almacenada en alguna parte. Entonces se agrupa con el puntero a la función.
Ahora para cada clase que tenga virtual
funciones, el compilador crea una lista de ellas llamada tabla virtual . A continuación, agrega un puntero adicional a esta tabla a la clase (vptr). Así, por esta estructura de clases:
struct A
{
int a;
virtual void foo(){};
};
struct B : A
{
int b;
virtual void foo(){};
virtual void bar(){};
};
El compilador podría terminar haciendo de esta manera: 
así que un puntero de función miembro a una función virtual en realidad es necesario que haya un índice en la tabla virtual. Por lo tanto, un puntero de función miembro realmente necesita 1) posiblemente un puntero a la función, 2) posiblemente un ajuste del puntero this
, y 3) posiblemente un índice vtable. Para ser coherente, cada puntero de función miembro debe ser capaz de todos estos. Así que eso es 8
bytes para el puntero, 4
bytes para el ajuste,bytes para el índice, para 16
bytes en total.
Creo que esto es algo que realmente varía mucho entre los compiladores, y hay muchas optimizaciones posibles. Probablemente ninguno realmente lo implementa de la manera que he descrito.
Para un lote de detalles, consulte this (vaya a "Implementaciones de los punteros de función de miembro").
Esencialmente, el estándar no requiere punteros de datos, punteros de función y punteros de función de miembro para que todos tengan el mismo tamaño. Si quiere saber por qué no tienen el mismo tamaño en su plataforma, tendrá que preguntarle a los responsables de su compilador de C++. http://www.parashift.com/c++-faq/cant-cvt-memfnptr-to-voidptr.html http://www.parashift.com/c++-faq/cant-cvt-fnptr-to-voidptr.html – Cubic
@KirilKirov no hay problema. No siempre estoy siendo sarcástico :) –