c++ - sistemas - sistema de recomendacion tesis
Palabra clave "virtual" de C++ para funciones en clases derivadas. ¿Es necesario? (8)
Agregar la palabra clave "virtual" es una buena práctica, ya que mejora la legibilidad, pero no es necesario. Las funciones declaradas virtuales en la clase base y que tienen la misma firma en las clases derivadas se consideran "virtuales" de forma predeterminada.
Con la definición de estructura dada a continuación ...
struct A {
virtual void hello() = 0;
};
Enfoque n. ° 1:
struct B : public A {
virtual void hello() { ... }
};
Enfoque # 2:
struct B : public A {
void hello() { ... }
};
¿Hay alguna diferencia entre estas dos formas de anular la función de saludo?
Definitivamente incluiré la palabra clave Virtual para la clase infantil, porque yo. Legibilidad. ii. Esta clase hija se derivará más abajo, no quiere que el constructor de la clase derivada posterior llame a esta función virtual.
Hay una diferencia considerable cuando tiene plantillas y comienza a tomar clases base como parámetro (s) de plantilla:
struct None {};
template<typename... Interfaces>
struct B : public Interfaces
{
void hello() { ... }
};
struct A {
virtual void hello() = 0;
};
template<typename... Interfaces>
void t_hello(const B<Interfaces...>& b) // different code generated for each set of interfaces (a vtable-based clever compiler might reduce this to 2); both t_hello and b.hello() might be inlined properly
{
b.hello(); // indirect, non-virtual call
}
void hello(const A& a)
{
a.hello(); // Indirect virtual call, inlining is impossible in general
}
int main()
{
B<None> b; // Ok, no vtable generated, empty base class optimization works, sizeof(b) == 1 usually
B<None>* pb = &b;
B<None>& rb = b;
b.hello(); // direct call
pb->hello(); // pb-relative non-virtual call (1 redirection)
rb->hello(); // non-virtual call (1 redirection unless optimized out)
t_hello(b); // works as expected, one redirection
// hello(b); // compile-time error
B<A> ba; // Ok, vtable generated, sizeof(b) >= sizeof(void*)
B<None>* pba = &ba;
B<None>& rba = ba;
ba.hello(); // still can be a direct call, exact type of ba is deducible
pba->hello(); // pba-relative virtual call (usually 3 redirections)
rba->hello(); // rba-relative virtual call (usually 3 redirections unless optimized out to 2)
//t_hello(b); // compile-time error (unless you add support for const A& in t_hello as well)
hello(ba);
}
La parte divertida es que ahora puede definir funciones de interfaz y no de interfaz para definir clases. Esto es útil para interfaces de interfuncionamiento entre bibliotecas (no confíe en esto como un proceso de diseño estándar de una sola biblioteca). No le cuesta nada permitir esto para todas sus clases, incluso podría typedef
B a algo si lo desea.
Tenga en cuenta que, si hace esto, también puede declarar constructores de copiar / mover como plantillas: permitir construir desde diferentes interfaces le permite "lanzar" entre diferentes tipos B<>
.
Es cuestionable si debe agregar soporte para const A&
in t_hello()
. La razón habitual para esta reescritura es alejarse de la especialización basada en herencia a la basada en plantillas, principalmente por motivos de rendimiento. Si continúa admitiendo la interfaz anterior, difícilmente podrá detectar (o disuadir) el uso anterior.
La ''virtualidad'' de una función se propaga de forma implícita, sin embargo, al menos un compilador que uso generará una advertencia si la palabra clave virtual
no se usa explícitamente, por lo que puede usarla solo para mantener el compilador en silencio.
Desde un punto de vista puramente estilístico, la palabra clave virtual
claramente "publicita" el hecho de que la función es virtual. Esto será importante para cualquier otra subclase B sin tener que verificar la definición de A. Para las jerarquías de clase profunda, esto se vuelve especialmente importante.
La palabra clave virtual
no es necesaria en la clase derivada. Aquí está la documentación de respaldo, del Estándar de Borrador C ++ (N3337) (énfasis mío):
10.3 Funciones virtuales
2 Si una función de miembro virtual
vf
se declara en una claseBase
y en una claseDerived
, derivada directa o indirectamente deBase
, una función miembrovf
con el mismo nombre, parameter-type-list (8.3.5), cv-qualification, y ref-qualifier (o ausencia de la misma) comoBase::vf
se declara, luegoDerived::vf
también es virtual ( esté o no declarado ) y anulaBase::vf
.
No hay diferencia para el compilador, cuando escribe lo virtual
en la clase derivada u omitirlo.
Pero necesita ver la clase base para obtener esta información. Por lo tanto, recomendaría agregar la palabra clave virtual
también en la clase derivada, si desea mostrarle al humano que esta función es virtual.
No, no se requiere la palabra clave virtual
en las anulaciones de funciones virtuales de las clases derivadas. Pero vale la pena mencionar una trampa relacionada: una falla al anular una función virtual.
La omisión de anulación se produce si tiene la intención de anular una función virtual en una clase derivada, pero comete un error en la firma para que declare una función virtual nueva y diferente. Esta función puede ser una sobrecarga de la función de clase base, o puede diferir en el nombre. Ya sea que utilice o no la palabra clave virtual
en la declaración de la función de clase derivada, el compilador no podrá decir que tiene la intención de anular una función de una clase base.
Sin embargo, este inconveniente es abordado por la característica del lenguaje de anulación explícita de C ++ 11, que permite que el código fuente especifique claramente que una función miembro está destinada a anular una función de clase base:
struct Base {
virtual void some_func(float);
};
struct Derived : Base {
virtual void some_func(int) override; // ill-formed - doesn''t override a base class method
};
El compilador emitirá un error en tiempo de compilación y el error de programación será inmediatamente obvio (quizás la función en Derived debería haber tomado un float
como argumento).
Consulte WP: C ++ 11 .
Son exactamente lo mismo. No hay diferencia entre ellos aparte de que el primer enfoque requiere más tipeo y es potencialmente más claro.