Pregunta ¿Deben implementarse TODAS las funciones virtuales en las clases derivadas?


Esto puede parecer una pregunta simple, pero no puedo encontrar la respuesta en ningún otro lado.

Supongamos que tengo lo siguiente:

class Abstract {
public:
    virtual void foo() = 0;
    virtual void bar();
}

class Derived : Abstract {
public:
    virtual void foo();
}

¿Está bien que la clase derivada no implemente la función bar ()? ¿Qué sucede si no TODAS mis clases derivadas necesitan la función bar (), pero algunas sí lo hacen? ¿Deben implementarse todas las funciones virtuales de una clase base abstracta en las clases derivadas, o simplemente las que son puramente virtuales? Gracias


75
2018-01-19 18:51


origen


Respuestas:


Las clases derivadas hacen no tiene que implementar todas funciones virtuales en sí mismas. Solo necesitan implementar el puro unos.1 Eso significa que Derived clase en la pregunta es correcta. Eso hereda el bar implementación desde su clase antecesora, Abstract. (Esto supone que Abstract::bar está implementado en algún lugar. El código en la pregunta declara el método, pero no lo define. Puedes definirlo en línea como La respuesta de Trenki muestra, o puede definirlo por separado).


1 E incluso entonces, solo si la clase derivada va a ser instanciado. Si una clase derivada no se crea una instancia directamente, sino que solo existe como una clase base de más clases derivadas, entonces es aquellos clases que son responsables de tener todos sus métodos virtuales puros implementados. La clase "intermedia" en la jerarquía puede dejar sin implementar algunos métodos virtuales puros, al igual que la clase base. Si la clase "media" hace implementar un método virtual puro, luego sus descendientes heredarán esa implementación, por lo que no tienen que volver a implementarlo ellos mismos.


64
2018-01-19 18:52



Solo los métodos virtuales puros deben implementarse en clases derivadas, pero aún necesita una definición (y no solo una declaración) de los otros métodos virtuales. Si no proporciona uno, el vinculador podría muy bien quejarse.

Entonces, solo poniendo {} después de que su método virtual opcional le dé una implementación predeterminada vacía:

class Abstract {
public:
    virtual void foo() = 0; // pure virtual must be overridden
    virtual void bar() {}   // virtual with empty default implementation
};

class Derived : Abstract {
public:
    virtual void foo();
};

Sin embargo, una implementación predeterminada más complicada entraría en un archivo fuente separado.


33
2018-01-19 19:00



El estándar ISO C ++ especifica que deben definirse todos los métodos virtuales de una clase que no son puros virtuales.

Simplemente ponga la regla es:
Si su clase derivada excede el método virtual de la clase Base, entonces debería proporcionar también una definición. De lo contrario, la clase Base debería proporcionar la definición de ese método.

De acuerdo con la regla anterior en su ejemplo de código, virtual void bar(); necesita una definición en la clase Base.

Referencia:

Estándar C ++ 03: 10.3 Funciones virtuales [class.virtual] 

Una función virtual declarada en una clase debe ser definida, o declarada pura (10.4) en esa clase, o ambas; pero no se requiere diagnóstico (3.2).

Entonces, debe hacer que la función sea puramente virtual o proporcionarle una definición.

los gcc faq doccumentos también:

El Estándar ISO C ++ especifica que todos los métodos virtuales de una clase que no son puros virtuales deben definirse, pero no requieren ningún diagnóstico para violaciones de esta regla [class.virtual]/8. En función de esta suposición, GCC solo emitirá los constructores definidos implícitamente, el operador de asignación, el destructor y la tabla virtual de una clase en la unidad de traducción que define su primer método no en línea.

Por lo tanto, si no define este método particular, el vinculador puede quejarse de la falta de definiciones para símbolos aparentemente no relacionados. Desafortunadamente, para mejorar este mensaje de error, puede ser necesario cambiar el enlazador, y esto no siempre se puede hacer.

La solución es garantizar que todos los métodos virtuales que no son puros estén definidos. Tenga en cuenta que un destructor debe definirse incluso si se declara puro-virtual [class.dtor]/7.


7
2018-01-19 19:10



Sí, está bien ... solo necesita implementar funciones virtuales puras para instanciar una clase derivada de una clase base abstracta.


3
2018-01-19 18:52



Sí, es correcto que una clase derivada tiene que OVERRIDE la función que es Pure Virtual en la clase para padres. La clase para padres que tiene una función virtual pura se llama clase abstracta solo porque su clase infantil debe dar su propio cuerpo de la función virtual pura.

Para las funciones virtuales normales: - No es necesario anularlos más, ya que algunas clases infantiles pueden tener esa función, algunas pueden no tenerla.

El principal objetivo del mecanismo de función virtual es el polimorfismo de tiempo de ejecución, ya sea que el objetivo principal de la función virtual pura (clase abstracta) sea hacer que sea obligatorio tener el mismo nombre Función con el propio cuerpo.


0
2018-01-19 19:36