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).
¿Fue útil?

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, con foo () siendo virtual y ejecutándose en la clase Child .
  • Lo mismo con BaseB , también se compilará y ejecutará según lo previsto, con foo () siendo virtual () y ejecutándose en la clase Child .
  • Con BaseC , sin embargo, se compilará y ejecutará, pero ejecutará la versión BaseC si la llama desde el contexto de BaseC , y la versión Child si llama con el contexto de Child .

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top