¿Cuál es el significado de clang’s -Wweak-vtables?

Básicamente no entiendo clang‘s -Wweak-vtables . Esto es lo que observé hasta ahora:

Primer caso: (desencadena la advertencia)

 class A { public: virtual ~A(){} }; class B : public A { public: virtual ~B(){} }; int main(){} 

Caso dos: (No desencadena advertencia)

 class A { public: virtual ~A(){} }; int main(){} 

Caso tres: (No desencadena advertencia)

 class A { public: virtual ~A(); }; A::~A(){} class B : public A { public: virtual ~B(){} }; int main(){} 

Caso cuatro: (advertencia de disparadores)

 class A { public: virtual ~A(){} virtual void fun(){} }; class B : public A { public: virtual ~B(){} }; int main(){} 

Caso cinco: (No desencadena advertencia)

 class A { public: virtual ~A(){} virtual void fun(); }; class B : public A { public: virtual ~B(){} }; int main(){} 

Caso seis: (No desencadena advertencia)

 class A { public: virtual ~A(){} virtual void fun(){} }; class B : public A {}; int main(){} 

Caso siete: (No desencadena advertencia)

 class A { public: virtual ~A(){} virtual void fun(){} }; class B : public A { public: virtual void fun(){} }; int main(){} 

La advertencia exacta es

 warning: 'A' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit [-Wweak-vtables] 

Entonces, aparentemente, si no declaro una función virtual no en línea en una clase, causa algún tipo de problema si y solo si derivo de ella y si la clase derivada tiene un destructor virtual.

Preguntas:

  1. ¿Por qué es esto un problema?
  2. ¿Por qué esto se soluciona al declarar una función virtual? (Advertencia habla de definiciones)
  3. ¿Por qué la advertencia no ocurre cuando no provengo de la clase?
  4. ¿Por qué la advertencia no ocurre cuando la clase derivada no tiene un destructor virtual?

Si todos virtual métodos virtual de una clase están en línea, el comstackdor no tiene forma de seleccionar una unidad de traducción en la que colocar una única copia compartida del vtable; en su lugar, debe colocarse una copia del vtable en cada archivo de objeto que lo necesite . En muchas plataformas, el vinculador puede unificar estas copias múltiples, descartando definiciones duplicadas o asignando todas las referencias a una copia, por lo que esto es solo una advertencia.

La implementación de una función virtual fuera de línea permite al comstackdor seleccionar la unidad de traducción que implementa ese método fuera de línea como un “hogar” para los detalles de implementación de la clase, y coloca la única copia compartida del vtable en la misma traducción unidad. Si varios métodos están fuera de línea, el comstackdor puede hacer una elección arbitraria del método, siempre que esa elección esté determinada únicamente por la statement de la clase; por ejemplo, GCC elige el primer método no en línea en el orden de statement.

Si no anula ningún método de una clase, la palabra clave virtual no tiene ningún efecto observable, por lo que no es necesario que el comstackdor emita un vtable para la clase. Si no se deriva de A , o si no declara virtual destructor de una clase derivada, no hay métodos anulados en A y, por lo tanto, se omite el vtable de A Si declara un método virtual fuera de línea adicional para suprimir la advertencia y también hace algo que anula un método en A , la implementación de la versión virtual no en línea (y su copia acompañante de la tabla vtable) debe suministrarse en una unidad de traducción vinculada; de lo contrario, el enlace fallará debido a que falta la variable vtable.