c++ - online - gcc compiler
Advertencia del compilador GNU "la clase tiene funciones virtuales pero destructor no virtual" (7)
He definido una interfaz en C ++, es decir, una clase que contiene solo funciones virtuales puras.
Quiero prohibir explícitamente a los usuarios de la interfaz eliminar el objeto a través de un puntero a la interfaz, por lo que he declarado un destructor protegido y no virtual para la interfaz, algo así como:
class ITest{
public:
virtual void doSomething() = 0;
protected:
~ITest(){}
};
void someFunction(ITest * test){
test->doSomething(); // ok
// deleting object is not allowed
// delete test;
}
El compilador de GNU me da una advertencia que dice:
clase ''ITest'' tiene funciones virtuales pero destructor no virtual
Una vez que el destructor está protegido, ¿cuál es la diferencia al tenerlo virtual o no virtual?
¿Crees que esta advertencia se puede ignorar o silenciar de forma segura?
Algunos de los comentarios sobre esta respuesta se refieren a una respuesta anterior que di, que fue incorrecta.
Un destructor protegido significa que solo se puede invocar desde una clase base, no a través de eliminar. Eso significa que un ITest * no se puede eliminar directamente, solo una clase derivada puede hacerlo. La clase derivada puede querer un destructor virtual. No hay nada de malo en tu código.
Sin embargo, dado que no se puede deshabilitar localmente una advertencia en GCC, y usted ya tiene un vtable, podría considerar hacer el destructor virtual de todos modos. Te costará 4 bytes para el programa (no por instancia de clase), como máximo. Como es posible que hayas dado a tu clase derivada un dtor virtual, es posible que no te cueste nada.
Es más o menos un error en el compilador. Tenga en cuenta que en las versiones más recientes del compilador esta advertencia no se lanza (al menos en 4.3 no). Tener el destructor protegido y no virtual es completamente legítimo en su caso.
Vea here un excelente artículo de Herb Sutter sobre el tema. Del artículo:
Directriz # 4: Un destructor de clase base debe ser público y virtual, o protegido y no virtual.
Es una clase de interfaz, por lo que es razonable que no deba eliminar los objetos que implementan esa interfaz a través de esa interfaz. Un caso común de eso es una interfaz para objetos creados por una fábrica que debería devolverse a la fábrica. (Tener objetos que contengan un puntero a su fábrica puede ser bastante caro).
Estoy de acuerdo con la observación de que GCC está gimiendo. En su lugar, debería simplemente advertir cuándo elimina un ITest *. Ahí es donde reside el peligro real.
Mi opinión personal es que harías lo correcto y el compilador está roto. Desactivaría la advertencia (localmente en el archivo que define la interfaz) si es posible,
Me parece que uso este patrón (pequeña ''p'') bastante. De hecho, me parece que es más común que mis interfaces tengan direcciones protegidas que para las públicas. Sin embargo, no creo que en realidad sea tan común una expresión idiomática (no se habla mucho de eso) y supongo que cuando la advertencia se agregó a GCC, era apropiado intentar y exigir que la versión anterior fuera virtual. tener la regla de las funciones virtuales. Personalmente, actualicé esa regla para ''dtor debe ser virtual si tiene funciones virtuales y desea que los usuarios puedan eliminar instancias de la interfaz a través de la interfaz, de lo contrario el dtor debería estar protegido y no virtual'' hace años;)
Si el destructor es virtual, se asegura de que el destructor de la clase base también se llame antes de realizar la limpieza, de lo contrario, pueden producirse algunas filtraciones de ese código. Por lo tanto, debe asegurarse de que el programa no tenga tales advertencias (preferiblemente, no hay advertencias).
Si insiste en hacer esto, continúe y pase -Wno-non-virtual-dtor
a GCC. Esta advertencia no parece activada de manera predeterminada, por lo que debe haberla habilitado con -Wall
o -Weffc++
. Sin embargo, creo que es una advertencia útil, porque en la mayoría de las situaciones esto sería un error.
Si tenía un código en uno de los métodos de ITest
que intentaba delete
sí mismo (una mala idea, pero legal), no se llamaría al destructor de la clase derivada. Aún debe hacer que su destructor sea virtual, incluso si nunca tiene la intención de eliminar una instancia derivada a través de un puntero de clase base.