2010-06-20 12 views
12

Los destructores no son virtuales de forma predeterminada para no dañarse cuando no es necesario, lo cual está bien.¿Por qué los destructores virtuales (C++) no se aplican para una clase base

Pero en el caso de un escenario clase clase derivada, ¿hay algún caso de uso para no tener un destructor virtual? Si no, podría ser posible (tiene sentido) que el compilador se queje si una clase se deriva de una clase base que tiene un destructor público no virtual (o no destructor) definido. Y no solo advertir sobre eso.

+0

Sutter escribió sobre eso en [Virtuality] (http://www.gotw.ca/publications/mill18.htm). –

+0

que fue una lectura increíble! gracias –

Respuesta

12

El problema con su idea es que es concebible que alguien esté usando un destructor de clase base no virtual como una optimización (si nunca va a destruir mediante un puntero de clase base, entonces la falta de virtual no te lastimó y todavía evita la entrada de vtable).

Dado que PODRÍA ser utilizado, está permitido. Creo que una advertencia de compilador opcional podría ser una buena idea, pero no algo en la especificación del lenguaje.

+1

Esta es básicamente la única razón por la que no quiere un destructor virtual en una clase base. En situaciones integradas asumir el riesgo y la responsabilidad de un destructor no virtual vale la pena el costo de la memoria. –

+4

@Michael Kohne: Entonces debe hacer que el destructor esté "protegido" para que alguien no pueda destruir inadvertidamente usando un puntero de clase base. –

+8

Take boost :: noncopyable, por ejemplo. Está destinado a ser heredado de, pero nunca vas a lanzar a esa clase base y eliminar, por lo que no necesita un dtor virtual. Y tener uno obligaría a muchísimas clases a incluir tablas que de lo contrario se podrían evitar. – jalf

8

Porque es perfectamente válido tener un destructor no virtual. Si las subclases solo están diseñadas para ser asignadas a la pila, por ejemplo, no hay necesidad de un destructor virtual. ¿Por qué exigir que los clientes tengan toda la maquinaria vblbl cuando se supone que una clase solo es decoradora?

También tiene poco sentido tener un destructor virtual cuando una clase se debe heredar de forma privada (implementado en términos de).

Dicho todo esto, un destructor generalmente debe ser público y virtual o estar protegido, a menos que una clase no sea una clase base.

+1

"solo están diseñados para ser asignados a la pila". Solo es problemático cuando se invoca 'delete' en un objeto polimórfico desde un puntero' base'. es decir, está bien asignar la clase derivada en el montón, incluso si el destructor de la base no es virtual, siempre que elimine el objeto del puntero a la clase derivada pero no a la base. – AraK

+1

@AraK: Entonces haces el destructor 'protected' para que no puedan hacer eso. –

5

El destructor virtual solo es necesario si realiza la destrucción polimórfica del objeto a través de delete. Eso, a su vez, implica inmediatamente objetos asignados dinámicamente (new -ed).

Si no asigna objetos dinámicamente, no necesita el destructor virtual. Esto ofrece inmediatamente una fuente ilimitada de casos de uso cuando el destructor virtual en la clase base no es necesario.

Si asigna objetos dinámicamente, pero nunca los destruye polimórficamente, no necesita el destructor virtual. Esto agrega otro conjunto de casos de uso cuando el destrcutor virtual en la clase base no es necesario.

2

Hay diferentes temas con lo que se propone, la primera de las cuales ya están contempladas en otras respuestas: sólo es necesario destructores virtuales si la intención de eliminar a través de un puntero a una base (una recomendación general es proporcionar ya sea un público destructor virtual o un destructor no virtual protegido ya que eso inhibiría la eliminación a través de la clase base).

Hay otro problema en que cuando un compilador ve una definición de clase, posiblemente no pueda saber si se derivará o no. Considere si implementa una clase base en una unidad de traducción. En un momento posterior, deriva de la clase. Si esa derivación implicaría hacer que el constructor sea virtual, la traducción de la clase base tendría que recompilarse, o bien la ODR (Regla de una sola definición) se rompería en su programa.

Si agrega otras unidades de traducción a la mezcla, las cosas empeoran.Siempre que incluya un archivo de encabezado de una unidad de traducción, se le forzará también a manualmente incluir al menos un encabezado donde se define un objeto derivado de esa clase (aumentar el acoplamiento), o bien, de nuevo, el compilador generaría una definición diferente para esa clase única en esa unidad de traducción (en comparación con la unidad de traducción donde se define la clase derivada) rompiendo nuevamente la ODR.

El problema es que el compilador solo tiene una vista parcial de su proyecto, y realmente no puede inferir lo que necesita/quiere de lo que ve.

Cuestiones relacionadas