2009-06-22 22 views
16

I tienen tres clases de base diferentes:C función ++ anulando

class BaseA 
{ 
public: 
    virtual int foo() = 0; 
}; 

class BaseB 
{ 
public: 
    virtual int foo() { return 42; } 
}; 

class BaseC 
{ 
public: 
    int foo() { return 42; } 
}; 

entonces derivo de la base como esto (sustituto X para A, B o C):

class Child : public BaseX 
{ 
public: 
    int foo() { return 42; } 
}; 

¿Cómo es la función de anulado en las tres clases base diferentes? ¿Son correctas mis tres suposiciones? ¿Hay alguna otra advertencia?

  • Con BaseA, la clase secundaria no compila, la función virtual pura no está definida.
  • Con BaseB, se llama a la función en el niño cuando se llama a foo en un BaseB * o un Niño *.
  • Con BaseC, la función en el elemento secundario se invoca al llamar a foo en Child * pero no en BaseB * (se llama a la función en la clase principal).

Respuesta

13

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

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 son siempre virtuales. Por lo tanto, está anulado 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 instanciar directamente BaseA).

Con C, sin embargo, la función no se reemplaza, sino que se sobrecarga. En esa situación, solo importa el tipo estático: lo llamará en lo que es un puntero (el tipo estático) en lugar de lo que realmente es el objeto (el tipo dinámico)

0

clase hija se compila si derivado de A, que 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 de nuevo.

2

Con BaseA, la clase de niño no de compilación, la función virtual pura no se define

Esto es cierto sólo si se intenta crear un objeto de BaseA.Si crea un objeto de niño y luego se le puede llamar foo() utilizando BaseA * o Child *

Con BaseB, la función en el niño se llama cuando se llama foo en un BaseB * o Child * .

Depende del tipo de objeto, ya que el objeto puede ser BaseB o Child. Si el objeto es BaseB, se llama a BaseB :: foo.

Con BASEC, theFunction en el niño se llama cuando se llama foo en Infantil * pero no en BaseB * (la función en clase padre se llama).

Sí, pero nunca desea hacer esto.

+0

¿Hay alguna razón específica por la que no quiero hacer esto? Aunque, por el contrario, no puedo encontrar un ejemplo donde * quiera * hacerlo. ¿Hay algún motivo técnico o simplemente se considera "mala práctica"? – Mizipzor

+1

No veo ninguna razón técnica ... pero es realmente confuso. – Naveen

+0

@mizipzor Tal vez estés heredando de las clases de otros, pero no tienes su código. No es un diseño ideal, pero puede suceder. – Kae

2

Desde un punto de vista de 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, por lo tanto, use con prudencia.

1

En su mayoría depende de cómo lo haya llamado.

si lo hizo:

class Child : public BaseA 
{ 
public: 
    int foo() { return 42; } 
}; 

e hizo

BaseA baseA = new Child(); 
baseA->foo(); 

Sería llamar a la función foo del niño.

Sin embargo, si se hizo esto:

BaseA baseA = new BaseA(); 

Se produciría un error de tiempo de compilación.