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:
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.