Los métodos, internamente, no son miembros de las funciones.
En la memoria, código y datos están en segmentos separados, ya de por sí no pueden pertenecer al mismo objeto.
Después está la forma en que C++ nombra a los métodos. Las clases pueden compartir el mismo nombre en sus métodos y los propios métodos con los mismos nombres pero diferente firma hacen cosas diferentes. El compilador, a la hora de generar la tabla de símbolos y saber a qué método referirse, lo que hace es decorarlos. Partiendo de su nombre le suma a éste datos de la firma e incluso puede añadir el nombre de la base.
Así se puede modificar un poco tu ejemplo anterior para que veas que, a pesar de que se generan tres objetos CNieto, cada uno con su propio espacio, su método Funcion48 son exactamente el mismo, es decir, sólo hay una copia de ellos en memoria. Lo que nos lleva a concluir que no son miembros propiamente dichos de la clase.
#include <cstdio>
#include <cstddef>
class CAbuelo
{
public:
virtual void Funcion1() {}
virtual void Funcion2() {}
virtual void Funcion3() {}
// ....
virtual void Funcion20() {}
virtual void Funcion21() {}
};
class CPadre : CAbuelo
{
public:
virtual void Funcion22() {}
virtual void Funcion23() {}
// ....
virtual void Funcion45() {}
virtual void Funcion46() {}
virtual void Funcion47() {}
};
class CNieto : CPadre
{
public:
virtual void Funcion48() {}
virtual void Funcion49() {}
virtual void Funcion50() {}
// ....
virtual void Funcion101() {}
virtual void Funcion102() {}
virtual void Funcion103() {}
};
CNieto objNieto1;
CNieto objNieto2;
CNieto objNieto3;
int main()
{
printf("objNieto1: 0x%p\nobjNieto1.Funcion48(): 0x%p\n",
&objNieto1, &objNieto1.Funcion48);
puts("");
printf("objNieto2: 0x%p\nobjNieto2.Funcion48(): 0x%p\n",
&objNieto2, &objNieto2.Funcion48);
puts("");
printf("objNieto3: 0x%p\nobjNieto3.Funcion48(): 0x%p\n",
&objNieto3, &(objNieto3.Funcion48));
}