2012-06-03 18 views
7

¿Puede alguien explicar por qué el resultado del código siguiente sería "clase B :: 1"?El código ejecuta el método de clase derivado, pero obtiene el parámetro predeterminado del método de clase base

¿Por qué el método virtual de la clase derivada usa el parámetro predeterminado de una clase base y no el suyo? Para mí esto es bastante extraño. ¡Gracias por adelantado!

Código:

#include <iostream> 

using namespace std; 

class A 
{ 
public: 
    virtual void func(int a = 1) 
    { 
     cout << "class A::" << a; 
    } 
}; 

class B : public A 
{ 
public: 
    virtual void func(int a = 2) 
    { 
     cout << "class B::" << a; 
    } 
}; 

int main() 
{ 
    A * a = new B; 
    a->func(); 

    return 0; 
} 

Respuesta

6

Porque los argumentos predeterminados se resuelven según el tipo estático de this (es decir, el tipo de la variable en sí, como A& en A& a;).

La modificación de su ejemplo un poco:

#include <iostream> 

class A 
{ 
public: 
    virtual void func(int a = 1) 
    { 
     std::cout << "class A::" << a << "\n"; 
    } 
}; 

class B : public A 
{ 
public: 
    virtual void func(int a = 2) 
    { 
     std::cout << "class B::" << a << "\n"; 
    } 
}; 

void func(A& a) { a.func(); } 

int main() 
{ 
    B b; 
    func(b); 
    b.func(); 

    return 0; 
} 

Observamos la siguiente salida:

class B::1 
class B::2 

en acción en ideone.

No se recomienda que una función virtual cambie el valor predeterminado por este motivo. Lamentablemente, no conozco ningún compilador que advierta sobre este constructo.


La explicación técnica es que hay dos maneras de tratar con argumento predeterminado:

  • crear una nueva función de actuar como trampolín: void A::func() { func(1); }
  • complemento en el argumento que falta en la llamada sitio de a.func() =>a.func(/*magic*/1)

Si se tratara de la primera (y suponiendo que la A::func w como declaró virtual también), entonces funcionaría como esperabas. Sin embargo, esta última forma fue elegida, ya sea porque los problemas con virtual no estaban previstos en ese momento o porque se consideraron irrelevantes frente a los beneficios (si los hubiera).

5

Puesto que el valor por defecto es sustituido durante la compilación y se toma de declaración, mientras que la función real para ser llamado (A o B :: func :: func) se determina en tiempo de ejecución.

+0

Gracias por la respuesta rápida! – Aremyst

5

Porque el polimorfismo en C++ tiene efecto en el tiempo de ejecución, mientras que la sustitución de los parámetros por defecto surte efecto en tiempo de compilación. En tiempo de compilación, el compilador no sabe (y se supone que no debe saber) el tipo dinámico del objeto al que apunta el puntero a. Por lo tanto, toma el argumento predeterminado para el único tipo que conoce para a, que en su ejemplo es A *.

(Esto por cierto es también la razón por defecto parámetros se dan en interfaces/cabeceras en lugar de en las implementaciones y/o definiciones. El compilador no inserta el parámetro por defecto en el código de la máquina de la aplicación, pero sólo en el código máquina de la persona que llama. Técnicamente , el parámetro predeterminado es propiedad de la persona que llama y la persona que llama no sabe, y no debería necesitar, el tipo dinámico de un objeto).

+0

¡Su respuesta es muy clara, gracias! – Aremyst

Cuestiones relacionadas