2011-03-11 12 views
9

ho queste classi:C++ il polimorfismo e di default argomento

class Base 
{ 
    public: 
     virtual void foo(int x = 0) 
     { 
      printf("X = %d", x); 
     } 
}; 

class Derived : public Base 
{ 
    public: 
     virtual void foo(int x = 1) 
     { 
      printf("X = %d", x); 
     } 
};

Quando ho:

Base* bar = new Derived(); 
bar->foo();

La mia uscita è "X = 0", anche se foo è chiamata dal derivato, ma quando Ho:

Derived* bar = new Derived(); 
bar->foo();

La mia uscita è "X = 1". Questo comportamento è corretto? (Per selezionare il valore del parametro predefinito dal tipo di dichiarazione, anziché selezionarlo dal tipo di oggetto effettivo). Questo rompe il polimorfismo del C++?

Può causare molti problemi se qualcuno utilizza le funzioni virtuali senza specificare il parametro della funzione effettiva e utilizza il parametro predefinito della funzione.

+1

inserire qualcosa nel printf() che in realtà indica quale funzione viene chiamata – Ferruccio

+0

È chiaro che la funzione chiamata è Derivata :: pippo – Felics

+0

Come? entrambi stampano qualcosa come "X = valore". Non è possibile utilizzare il valore per determinare quale viene chiamato. Prova a stampare "Base: X =% d" nella base e sarai in grado di dire quale viene chiamato. – Ferruccio

risposta

5

Gli argomenti predefiniti vengono mantenuti anche se si esegue l'override di una funzione! E questo comportamento è corretto. Fammi cercare il riferimento dallo standard C++.

§8.3.6/10 [argomenti di default] dal ++ standard C dice,

Una funzione virtuale chiamata (10,3) utilizza gli argomenti di default nel dichiarazione della funzione virtuale determinato dalla il tipo statico del puntatore o riferimento che indica l'oggetto . Una funzione di override in una classe derivata non acquisisce gli argomenti di default dalla funzione sostituisce.

L'esempio dalla norma stessa

struct A { 
    virtual void f(int a = 7); 
}; 
struct B : public A { 
    void f(int a); 
}; 
void m() 
{ 
    B* pb = new B; 
    A* pa = pb; 
    pa->f(); //OK, calls pa->B::f(7) 
    pb->f(); //error: wrong number of arguments for B::f() 
} 

Inoltre, non solo è conservato, viene valutato ogni volta che la funzione viene chiamata:

§8.3.6/9 dice,

Gli argomenti predefiniti vengono valutati ogni ora la funzione è chiamata

+0

@Nawaz: copia/incolla da un'altra risposta invece di il collegamento ad esso in realtà non aiuta SO nel suo insieme. Soprattutto quando qualcun altro ha già fornito il link. – Jon

+0

@Jon: copia incolla quale altra risposta? Vuoi dire che copio incollato da un'altra risposta? Quale risposta? – Nawaz

+0

@Jon: Va bene. Dico la tua risposta ORA. Ma se pensi che risponda alla domanda, allora dovresti dire duplicare l'argomento e votare per chiuderlo! – Nawaz

5

Il comportamento è corretto. Controlla la risposta a questa domanda per una spiegazione:

Can virtual functions have default parameters?

Morale: trattare i valori dei parametri di default come parte della firma della funzione e non modificano li quando l'override funzioni virtuali!

+0

@Jon, grazie per il link, la risposta originale ottiene decisamente un uptote da me ... – Nim

+0

@Jon: Se pensi che questo link risponda alla domanda, allora dovresti votare per chiudere questo argomento, essendo possibile duplicare! – Nawaz

+0

@Nawaz: come ho già detto: la * risposta * a quella domanda risponde anche a questa. Le domande stesse * non * sono le stesse. – Jon

0

Questo è ciò che C++ ha progettato, penso.

Il polimorfismo è terminato dalla tabella virtuale, che gioca internamente con il puntatore alle funzioni, ma il valore predefinito del parametro non è memorizzato con il puntatore della funzione, è vincolato nella fase di compilazione, quindi può solo ottenere il valore predefinito prima guardando il suo tipo, nel primo caso, è Base, quindi usa 0 come valore predefinito.

+0

Questo è tecnicamente corretto, ma fuorviante come risposta perché lo standard C++ non impone che il polimorfismo sia implementato da vtables. Specifica in modo specifico cosa dovrebbe accadere in tali scenari; se non fosse definito come un dettaglio di implementazione, chiunque poteva scrivere un compilatore conforme che usava un meccanismo come un vtable per legare i valori predefiniti. – Jon

+0

Sì. Ma per quei ragazzi che lavorano su standard, pensano anche se la funzionalità è pratica. Penso che sia stato progettato in questo modo perché l'altro modo non è pratico. Qualsiasi funzione può richiedere a molti colleghi che possono avere valori predefiniti. Ciò rende il runtime vincolare una missione impossibile. – Shuo