Anulación de la función C ++
-
06-07-2019 - |
Pregunta
Tengo tres clases base diferentes:
class BaseA
{
public:
virtual int foo() = 0;
};
class BaseB
{
public:
virtual int foo() { return 42; }
};
class BaseC
{
public:
int foo() { return 42; }
};
Luego obtengo de la base de esta manera (sustituya X por A, B o C):
class Child : public BaseX
{
public:
int foo() { return 42; }
};
¿Cómo se anula la función en las tres clases base diferentes? ¿Son correctos mis tres supuestos siguientes? ¿Hay alguna otra advertencia?
- Con BaseA, la clase secundaria no se compila, la función virtual pura no está definida.
- Con BaseB, la función en el niño se llama cuando se llama foo en un BaseB * o Niño *.
- Con BaseC, la función en el niño se llama cuando se llama foo en Niño * pero no en BaseB * (se llama a la función en la clase padre).
Solución
En la clase derivada, un método es virtual si se define virtual en la clase base, incluso si la palabra clave virtual no se usa en el método de la clase derivada.
- Con
BaseA
, se compilará y ejecutará según lo previsto, confoo ()
siendo virtual y ejecutándose en la claseChild
. - Lo mismo con
BaseB
, también se compilará y ejecutará según lo previsto, confoo ()
siendo virtual () y ejecutándose en la claseChild
. - Con
BaseC
, sin embargo, se compilará y ejecutará, pero ejecutará la versiónBaseC
si la llama desde el contexto deBaseC
, y la versiónChild
si llama con el contexto deChild
.
Otros consejos
La regla importante para recordar es que una vez que una función se declara virtual, las funciones con firmas coincidentes en las clases derivadas siempre son virtuales. Por lo tanto, se anula para Child of A y Child of B, que se comportarían de manera idéntica (con la excepción de que no se puede crear una instancia directa de BaseA).
Con C, sin embargo, la función no se anula, sino que se sobrecarga. En esa situación, solo importa el tipo estático: lo llamará a lo que es un puntero (el tipo estático) en lugar de lo que realmente es el objeto (el tipo dinámico)
Con BaseA, la clase secundaria no compilar, la función virtual pura no está definido
Esto es cierto solo si intenta crear un objeto de BaseA. Si crea un objeto Child y luego puede llamar a foo () usando BaseA * o Child *
Con BaseB, la función en el hijo se llama al llamar a foo en una BaseB * o Niño *.
Depende del tipo de objeto, ya que el objeto puede ser BaseB o Hijo. Si el objeto es BaseB, se llama BaseB :: foo.
Con BaseC, la función en el niño se llama cuando se llama foo on Child * pero no en BaseB * (la función en la clase padre se llama).
Sí, pero nunca quieres hacer esto.
Desde el punto de vista del polimorfismo, prefiera A, para que sepa que cada niño tiene su propia implementación de la función virtual.
Elija B principalmente si tiene una implementación predeterminada válida, pero luego debe asegurarse de que todas las clases secundarias tengan su propia implementación según sea necesario.
C no es polimorfismo, así que úsalo juiciosamente.
Depende principalmente de cómo lo llamaste.
si lo hiciste:
class Child : public BaseA
{
public:
int foo() { return 42; }
};
y did
BaseA baseA = new Child();
baseA->foo();
Llamaría a la función foo de Child.
Sin embargo, si hiciste esto:
BaseA baseA = new BaseA();
Produciría un error de tiempo de compilación.
Class Child se compilará si se deriva de A, simplemente no puede crear instancias de objetos de ese tipo.
Esto podría ser valioso si fuera a anular algunas funciones de Base, y luego derivar nuevamente.