Si las clases con funciones virtuales son implementados con vtables, ¿cómo es una clase sin funciones virtuales implementadas?

StackOverflow https://stackoverflow.com/questions/101329

  •  01-07-2019
  •  | 
  •  

Pregunta

En particular, no tiene que haber algún tipo de puntero a función en lugar de todos modos?

¿Fue útil?

Solución

No virtual funciones miembro son realmente un azúcar sintáctico como son casi como un funcionamiento normal, pero con acceso de cheques y una implícita objeto de parámetro.

struct A 
{
  void foo ();
  void bar () const;
};

es básicamente la misma:

struct A 
{
};

void foo (A * this);
void bar (A const * this);

La vtable es necesario para que nos llame a la función correcta para nuestro objeto específico de la instancia.Por ejemplo, si tenemos:

struct A 
{
  virtual void foo ();
};

La aplicación de 'foo' podría aproximarse a algo como:

void foo (A * this) {
  void (*realFoo)(A *) = lookupVtable (this->vtable, "foo");
  (realFoo)(this);   // Make the call to the most derived version of 'foo'
}

Otros consejos

Creo que la frase "clases con funciones virtuales son implementados con vtables"es engañosa usted.

La frase la hace sonar como clases virtuales se han implementado funciones "en forma de Un"y clases virtuales se han implementado funciones "en modo B".

En realidad, las clases con funciones virtuales, además de la siendo implementados como clases son, también tienen una vtable.Otra forma de verlo es que "'vtables' implementación de la 'función virtual' parte de una clase".

Más detalles sobre cómo tienen tanto trabajo:

Todas las clases (virtual o no virtual métodos) son estructuras.El sólo la diferencia entre una estructura y una clase en C++ es que, de forma predeterminada, los miembros del público en las estructuras y privado en las clases.Debido a eso, voy a utilizar el término clase aquí para referirse tanto a las estructuras y clases.Recuerde, ellos son casi sinónimos!

Los Datos De Los Miembros De La

Las clases son (como son los structs) sólo los bloques de memoria contigua, donde cada miembro se almacena en la secuencia.Tenga en cuenta que algunas veces habrá huecos entre los miembros de la CPU razones arquitectónicas, por lo que el bloque puede ser mayor que la suma de sus partes.

Métodos

Los métodos o las "funciones miembro" son una ilusión.En realidad, no hay tal cosa como un "miembro de la función".Una función es siempre sólo una secuencia de instrucciones de código de máquina almacenado en algún lugar de la memoria.Para realizar una llamada, el procesador salta a la posición de memoria y comienza a ejecutar.Se podría decir que todos los métodos y funciones de 'global', y cualquier indicación de lo contrario es conveniente ilusión impuesta por el compilador.

Obviamente, un método que actúa como pertenece a un objeto específico, por lo que claramente hay más cosas.Atar a una llamada particular de un método (función) para un objeto específico, cada miembro del método tiene un oculto argumento que es un puntero al objeto en cuestión.El miembro es oculto en que no añada a su código de C++ a ti mismo, pero no hay nada mágico acerca de él-es muy real.Cuando dices esto:

void CMyThingy::DoSomething(int arg);
{
    // do something
}

El compilador realmente hace esto:

void CMyThingy_DoSomething(CMyThingy* this, int arg)
{
    /do something
}

Por último, al escribir esto:

myObj.doSomething(aValue);

el compilador dice:

CMyThingy_DoSomething(&myObj, aValue);

No hay necesidad de punteros a función en cualquier lugar!El compilador ya sabe cuál es el método que se llamaba así lo llama directamente.

Los métodos estáticos son aún más simple.Ellos no tienen un este puntero, por lo que se aplican exactamente como usted las escribe.

Eso es!El resto es sólo conveniente sintaxis de endulzamiento:El compilador sabe que clase de un método que pertenece, por lo que asegura que no te permite llamar a la función, sin especificar cuál.También utiliza ese conocimiento para que se traduce myItem a this->myItem cuando es inequívoco para hacerlo.

(sí, es correcto:acceso de los miembros de un método es siempre realiza de forma indirecta a través de un puntero, incluso si usted no ve uno)

(Editar:Eliminado de la última frase y publicado por separado, por lo que puede ser criticado por separado)

Los métodos virtuales son necesarios cuando se desea utilizar el polimorfismo.El virtual modificador pone el método en el VMT para el enlace y, a continuación, en tiempo de ejecución se decide qué método de qué clase se ejecuta.

Si el método no es virtual - se decide en tiempo de compilación a partir de la cual instancia de la clase va a ser ejecutado.

Los punteros de función se utilizan sobre todo para las devoluciones de llamada.

Si una clase con una función virtual se implementa con una vtable, y luego de una clase con ninguna función virtual se implementa sin una vtable.

Una vtable contiene los punteros de función necesaria para el envío de una llamada al método apropiado.Si el método no es virtual, la llamada pasa a la clase del tipo conocido, y ningún direccionamiento es necesario.

Para un no-método virtual, el compilador puede generar una normal invocación de función (por ejemplo, LLAMAR a una dirección en particular con este puntero que se pasa como parámetro) o incluso en línea es.Para una función virtual, el compilador no sabe en tiempo de compilación en la que la dirección de invocar el código, por tanto, se genera código que busca la dirección en la vtable en tiempo de ejecución y, a continuación, se invoca el método.Cierto, incluso para funciones virtuales el compilador a veces puede resolver correctamente el derecho de código en tiempo de compilación (por ejemplo, los métodos de variables locales invoca sin un puntero o referencia).

(Saqué esta sección de mi respuesta original para que pueda ser criticado por separado.Es mucho más conciso y al punto de tu pregunta, así que en cierto modo es una mucho mejor respuesta)

No, No hay punteros de función;en lugar de ello, el compilador convierte el problema dentro-fuera.

El compilador se llama a una función global con un puntero al objeto en lugar de llamar a algunos señaló a la función dentro del objeto

Por qué?Porque es por lo general mucho más eficiente de esa manera.Indirectos llamadas son caras instrucciones.

No hay necesidad de punteros a función ya que no puede cambiar durante la ejecución.

Las ramas se generan directamente en el código compilado de los métodos;al igual que si usted tiene funciones que no están en una clase en todas las ramas, se generan directamente a ellos.

El compilador/enlazador enlaces directamente los métodos que se invoca.No hay necesidad para una vtable direccionamiento indirecto.Por CIERTO, ¿qué tiene que ver con la "pila vsdel montón"?

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