2010-04-22 9 views
19

Empezar a utilizar PC-Lint en una base de código existente (miedo y temor).Destructores para clases similares a la interfaz C++

Una cosa que se queja es la siguiente:

class IBatch 
{ 
public: 
    virtual void StartBatch() =0; 
    virtual int CommitBatch() =0; 
}; 

cual, como otra clase deriva de este usarlo como una interfaz

base class 'IBatch' has no destructor 

Entonces, la pregunta: cuando se crea Interfaz clases como las anteriores, ¿siempre incluye un destructor virtual? ¿Por qué? (Se trata de un estilo o un error de codificación?)

EDIT: En caso de haber dicho que no espero ni quiero que el usuario de IBatch de destrucción, que es un consumidor de un servicio sólo, a través de esta interfaz para algunos clase de implementación externa (si eso marcara la diferencia)

+1

Como se dijo, necesita un DTor virtual. Como nota al margen: las interfaces COM en cambio se basan en 'Release()', que es un método virtual que puede redireccionar a un DTor derivado "apropiado". – peterchen

Respuesta

5

Si hay funciones virtuales, debe haber un destructor virtual. Siempre. No importa que solo sea una clase de interfaz, aún necesita el destructor virtual.

O eso, o necesita un protected destructor no virtual. Pero luego no puede eliminar el objeto usando el puntero de la interfaz.

+1

A menos que el destructor esté protegido (es decir, impide la eliminación mediante un puntero a interfaz). –

+0

@Steve: Hehe - corregido. –

2

Entonces, la pregunta: cuando se crea clases de interfaz como el de arriba, hacer de incluir siempre un destructor virtual? ¿Por qué? (¿Es un estilo o un error de codificación ?)

Bueno, realmente depende. Si alguna vez llama a eliminar en un puntero IBatch, probablemente no hará lo que está esperando. Por supuesto, si tienes algo como Inicial/Apagamiento virtual o AddRef/Releases, entonces no es realmente un problema.

4

Una clase con funciones virtuales pero sin destructor virtual es sospechosa, y muy probablemente incorrecta: vea una explicación buena y más precisa here.

7

¡Error de datos - El destructor para la clase derivada nunca se llama si se llama a través de puntero a la clase base.

Cuando se implementa IBatch y que se refieren a la clase derivada por un puntero a una clase base (puntero a IBatch) y se llama a delete en ese puntero a la clase base que podría terminar con la pérdida de memoria debido a que el destructor para su clase derivada nunca será llamada.

La regla básica es cuando una clase tiene al menos un método virtual que necesita tener virtual destructor.

class IBatch 
{ 
    public: 
     virtual void f() = 0; 
}; 

class A : public IBatch 
{ 
    public: 
     void f() {} 
     ~A() {} 
}; 

IBatch * a = new A(); 
a->f(); // calls A::f() 
delete a; // calls IBatch::~IBatch() not A::~A() 
+2

¿Qué pasa si no quiero que los usuarios de la interfaz de IBatch me llamen eliminar - es ahí donde entra la respuesta protegida y no virtual de @James? – sdg

+0

¿Qué quieres decir con 'me'? – stefanB

+1

@sdg: Sí. Un destructor protegido impide que * otras * clases (fuera de esa jerarquía de clase) invoquen eliminar en él. – Kissaki

0

compilador pone destructor por defecto que no es virtual, lo que implica que una 'Borrar' en un puntero a la clase base virtual va a tener éxito con una pérdida de memoria resultante. Por lo tanto, es un error de implementación, ni estilo ni error de codificación.

+0

En realidad, eliminar un objeto derivado con funciones virtuales mediante un puntero a una clase base sin un destructor virtual es un comportamiento indefinido. Por lo tanto, se trata de un error de codificación, y puede pasar cualquier cosa, incluida una pérdida de memoria, un bloqueo del programa o un caso de demonios nasales. – KeithB

Cuestiones relacionadas