2011-03-19 18 views
7

Cuando escribo clases interfaz en C++, que elige cualquiera de las siguientes 2 opcionesqué hacer con las destructores en una interfaz

class Interface 
{ 
public: 
    virtual R1 f1(p11, p12 , ...) = 0; 
    ... 
    virtual Rn fn(pn1, pn2 , ...) = 0; 
    virtual ~Interface() {} 
} 

o

class Interface 
{ 
public: 
    virtual R1 f1(p11, p12 , ...) = 0; 
    ... 
    virtual Rn fn(pn1, pn2 , ...) = 0; 
    virtual ~Interface() = 0; 
} 
Interface::~Interface() {} 

La primera versión es más corta de escribir
El segundo es atractivo en que todas las funciones de la interfaz son puramente virtuales

¿Hay alguna razón por la que preferiría uno u otro método (o tal vez un tercero)?
Gracias

Respuesta

5

Según tengo entendido, el propósito de hacer función virtual pura virtuales es forzar las clases derivadas o bien proporcionar la aplicación por ello o elegir la implementación predeterminada por explícitamente escribir Base::f() en el Derived::f().

Entonces, si eso es cierto, entonces ¿cuál es el propósito de hacer virtual destructor pure virtual? ¿Obliga a las clases derivadas a proporcionar implementación para Base::~Base()? ¿Pueden las clases derivadas implementar Base::~Base()? No.

Eso significa que la primera versión con virtual destructor parece suficiente para casi para todos los propósitos. Después de todo, el objetivo más común del destructor virtual es que los clientes pueden correctamente delete objetos de las clases derivadas a través de punteros del tipo Base*.

Sin embargo, si realiza todas las funciones de Base virtual única, nopura virtual y proporcionar implementaciones para ellos (en realidad usted tiene que ofrecer), y al mismo tiempo desea hacer Basetipo abstracto, y luego tener una pura destructor virtual en Base es la única solución:

class Base 
{ 
public: 
    virtual void f() {}; //not pure virtual 
    virtual ~Base() = 0; //pure - makes Base abstract type! 
}; 

Base::~Base() {} //yes, you have to do this as well. 

Base *pBase = new Base(); // error - cannot create instance! 

Espero que ayude.

1

En el primer caso, la clase derivada puede elegir si implementar un destructor o no. En el segundo caso, el destructor virtual puro debe ser anulado, por lo que la clase derivada se ve obligada a implementar un destructor.

A menos que tenga alguna razón por la que desea forzar esto, me gustaría ir con el primer caso.

+2

Mal. El segundo caso no fuerza al destructor a ser anulado: http://ideone.com/aw3kV. Además, esta frase * "para que la clase base se vea obligada a implementar un destructor" * no tiene sentido para mí. ¿Puedes reformularlo? – Nawaz

+0

@Nawaz - Lo siento, mal tipeo. Quise decir "derivado", no "base". Ahora está arreglado. Debe dejar de escribir el código a las 5:00 a.m. –

2

Para mí, el dtor no es parte de la interfaz. El fi() tendría análogos en otros idiomas, no el dtor. Del mismo modo, puede escribir condiciones previas y posteriores para el fi(), pero no para el dtor. Esto hace que sea solo una verruga de C++, y la primera técnica es la forma más cómoda de lidiar con ella.

+3

Verruga o no, C++ hace que el destructor sea parte de la interfaz. Si es virtual o no determina si los clientes pueden 'borrar 'válidamente una instancia de la clase derivada a través de un puntero a base. Acciones de cliente válidas == interfaz. Sin embargo, si es puro o no, no es parte de la interfaz externa, excepto como dice Nawaz si es la única función pura y, por lo tanto, hace que la clase sea abstracta. –

+1

Estoy de acuerdo, pero la pregunta es acerca de lo virtual versus virtual puro, no virtual versus no virtual. – fizzer

+0

OK, no entendí que quisieras decir que, en general, en C++, dtor no es parte de la interfaz. Estoy de acuerdo en esta pregunta, la diferencia entre las opciones ofrecidas no es parte de la interfaz. –

1

bien, que se encuentra en un enlace y así que pensé que lo mencionan como una respuesta:

Are inline virtual functions really a non-sense?

que he visto compiladores que no emiten ningún tabla v si no no la función en línea existe (y se define en un archivo de implementación en lugar de un encabezado ). Lanzarían los errores como faltando vtable-for-class-A o algo similar, y usted sería confundido como el infierno, como yo lo era.

De hecho, eso no conformes con la estándar, pero sucede así que considere poner al menos una función virtual no en la cabecera (aunque sólo lo virtual destructor), por lo que el compilador podría emitir una vtable para la clase en ese lugar. Sé que sucede con algunas versiones de gcc. (Johannes Schaub)

Es un poco diferente de su segundo caso (sugiere de tomar la función del archivo de cabecera por completo a fin de no ser víctima de un problema gcc), pero pensé que lo mencionan. Los inconvenientes de gcc pueden ocasionalmente morder.

Cuestiones relacionadas