El objeto foo
es una variable local con el tipo Foo*
. Esa variable probablemente se asigna en la pila para la función main
, al igual que cualquier otra variable local. Pero el valor almacenado en foo
es un puntero nulo. No apunta a ningún lado. No hay ninguna instancia del tipo Foo
representada en ningún lado.
Para llamar a una función virtual, la persona que llama necesita saber a qué objeto se está llamando la función. Eso se debe a que el objeto en sí es lo que le dice a qué función realmente se debe llamar. (Esto se implementa frecuentemente dando al objeto un puntero a un vtable, una lista de punteros a función, y quien llama simplemente sabe que se supone que debe llamar a la primera función de la lista, sin saber de antemano dónde señala ese puntero).
Pero para llamar a una función no virtual, la persona que llama no necesita saber todo eso. El compilador sabe exactamente a qué función se llamará, por lo que puede generar una instrucción de código de máquina CALL
para ir directamente a la función deseada. Simplemente pasa un puntero al objeto al que se llamó la función como un parámetro oculto de la función. En otras palabras, el compilador traduce su llamada a la función en esto:
void Foo_say_hi(Foo* this);
Foo_say_hi(foo);
Ahora, puesto que la aplicación de esa función nunca hace referencia a cualquiera de los miembros del objeto apuntado por su argumento this
, que esquivar efectivamente la bala de desreferenciando un puntero nulo porque nunca desreferencia uno.
Formalmente, llamar a cualquier función - incluso una no virtual - en un puntero nulo es un comportamiento indefinido. Uno de los resultados permitidos del comportamiento indefinido es que su código parece ejecutarse exactamente como lo desea. Usted no debe confiar en eso, aunque a veces encontrará bibliotecas de su compilador que hacen. Pero el proveedor del compilador tiene la ventaja de poder agregar una mayor definición a lo que de otro modo sería un comportamiento indefinido. No lo hagas tú mismo.
Ver [this] (http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in-undefined-behav) para qué el lenguaje dice al respecto Ambos son un comportamiento indefinido. – GManNickG