¿Final implica reemplazar?
Según entiendo, la palabra clave override
indica que una declaración dada implementa un método base virtual
, y la compilación debería fallar si no se encuentra ningún método base coincidente.
Mi comprensión de la palabra clave final
es que le dice al compilador que ninguna clase reemplazará esta función virtual
.
Entonces es override final
redundante? Parece compilar bien. ¿Qué información transmite override final
que final
no transmite? ¿Cuál es el caso de uso para tal combinación?
5 answers
final
no requiere que la función anule nada en primer lugar. Su efecto se define en [clase.virtual]/4 as
Si una función virtual
f
en alguna claseB
está marcada con especificador de virtfinal
y en una claseD
derivada deB
una funciónD::f
sobreescribeB::f
, el programa está mal formado.
Eso es todo. Ahora override final
simplemente significaría
"Esta función anula una clase base uno (override
) y no puede anularse (final
)."final
por sí solo impondría un requisito más débil.
override
y final
tienen un comportamiento independiente.
Tenga en cuenta que final
solo se puede usar para funciones virtuales, aunque - [clase.mem]/8
A virt-specifier-seq figurará únicamente en la declaración de A función miembro virtual (10.3).
De ahí la declaración
void foo() final;
Es efectivamente lo mismo que
virtual void foo() final override;
Dado que ambos requieren foo
para anular algo-la segunda declaración usando override
, y la primera siendo válida si y solo si foo
es implícitamente virtual, es decir, cuando foo
está sobreescribiendo una función virtual llamada foo
en una clase base, que hace que foo
en la derivada sea automáticamente virtual. Así, override
sería superfluo en declaraciones donde final
, pero no virtual
, ocurre.
Sin embargo, esta última declaración expresa la intención mucho más claramente y sin duda debería preferirse.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-03 12:22:50
final
no implica necesariamente que la función se anula. Es perfectamente válido (si tiene un valor algo dudoso) declarar una función virtual como final
en su primera declaración en la jerarquía de herencia.
Una razón que se me ocurre para crear una función virtual e inmediatamente final es si desea evitar que una clase derivada le dé al mismo nombre y parámetros un significado diferente.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-02 12:04:10
(Salta al final para ver la conclusión si tienes prisa.)
Tanto override
como final
pueden aparecer solo en la declaración en una función virtual. Y ambas palabras clave se pueden usar en la misma declaración de función, pero si es útil usarlas ambas depende de las situaciones.
Tome el siguiente código como ejemplo:
#include <iostream>
using std::cout; using std::endl;
struct B {
virtual void f1() { cout << "B::f1() "; }
virtual void f2() { cout << "B::f2() "; }
virtual void f3() { cout << "B::f3() "; }
virtual void f6() final { cout << "B::f6() "; }
void f7() { cout << "B::f7() "; }
void f8() { cout << "B::f8() "; }
void f9() { cout << "B::f9() "; }
};
struct D : B {
void f1() override { cout << "D::f1() "; }
void f2() final { cout << "D::f2() "; }
void f3() override final { cout << "D::f3() "; } // need not have override
// should have override, otherwise add new virtual function
virtual void f4() final { cout << "D::f4() "; }
//virtual void f5() override final; // Error, no virtual function in base class
//void f6(); // Error, override a final virtual function
void f7() { cout << "D::f7() "; }
virtual void f8() { cout << "D::f8() "; }
//void f9() override; // Error, override a nonvirtual function
};
int main() {
B b; D d;
B *bp = &b, *bd = &d; D *dp = &d;
bp->f1(); bp->f2(); bp->f3(); bp->f6(); bp->f7(); bp->f8(); bp->f9(); cout << endl;
bd->f1(); bd->f2(); bd->f3(); bd->f6(); bd->f7(); bd->f8(); bd->f9(); cout << endl;
dp->f1(); dp->f2(); dp->f3(); dp->f6(); dp->f7(); dp->f8(); dp->f9(); cout << endl;
return 0;
}
La salida es
B::f1() B::f2() B::f3() B::f6() B::f7() B::f8() B::f9()
D::f1() D::f2() D::f3() B::f6() B::f7() B::f8() B::f9()
D::f1() D::f2() D::f3() B::f6() D::f7() D::f8() B::f9()
-
Compare
f1()
yf6()
. Sabemos queoverride
yfinal
es independiente semáticamente.-
override
significa que la función está sobreescribiendo una función virtual en su clase base. Véansef1()
yf3()
. -
final
significa que la función no puede ser anulada por su clase derivada. (Pero la función en sí no necesita anular una función virtual de clase base.) Véansef6()
yf4()
.
-
Compare
f2()
yf3()
. Sabemos que si una función miembro se declara sinvirtual
y confinal
, significa que ya sobrescribe una función virtual en clase baja. En este caso, la palabra claveoverride
es redundante.Compare
f4()
yf5()
. Sabemos que si una función miembro se declara convirtual
y si no es la primero función virtual en la jerarquía de herencia, entonces deberíamos usaroverride
para especificar la relación de anulación. De lo contrario, podemos agregar accidentalmente una nueva función virtual en la clase derivada.Compare
f1()
yf7()
. Sabemos que cualquier función miembro, no solo los virtuales, puede ser anulado en clase derivada. Lo quevirtual
especifica es polimorfismo, lo que significa que la decisión sobre qué función ejecutar se retrasa hasta el tiempo de ejecución en lugar del tiempo de compilación. (Esto debe evitarse en la práctica.)Compare
f7()
yf8()
. Sabemos que incluso podemos anular una función de clase base y convertirla en una nueva función virtual. (Lo que significa que cualquier función miembrof8()
de clase derivada deD
será virtual.) (Esto debe evitarse en la práctica demasiado.)Compare
f7()
yf9()
. Sabemos queoverride
puede ayudarnos a encontrar el error cuando queremos sobrescribir una función virtual en clase derivada mientras olvidamos agregar la palabra clavevirtual
en clase base.
En conclusión , la mejor práctica en mi opinión es: {[38]]}
-
solo use
virtual
en la declaración de la primera función virtual en la clase base; - utilice siempre
override
para especificar la función virtual de anulación en clase derivada, a menos que también se especifiquefinal
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-25 12:04:34
No final
no implica necesariamente override
. De hecho, podrías declarar una función virtual
que declaras inmediatamente final
ver aquí . La palabra clave final
simplemente indica que ningún class
derivado puede crear una anulación de esta función.
La palabra clave override
es importante en el sentido de que obliga a que en realidad se está sobrescribiendo una función virtual (en lugar de declarar una nueva no relacionada). Ver este post con respecto a override
En resumen, cada uno de ellos sirven a su propio propósito particular, y a menudo es correcto usar ambos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:10
El siguiente código (con el especificador final
) compila. Pero la compilación falla cuando final
se reemplaza por override final
. Así, override final
transmite más información (e impide la compilación) que solo final
.
class Base
{
public:
virtual ~Base() {}
};
class Derived : public Base
{
public:
virtual void foo() final
{
std::cout << "in Derived foo\n";
}
};
Esencialmente, override final
dice que este método no puede ser anulado en ninguna clase derivada y este método anula un método virtual en una clase base. final
por sí solo no especifica la parte de sobreescritura de la clase base.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-06 08:28:29