2011-01-12 9 views
6
struct level0 
{ 
    virtual void foo() = 0; 
}; 

struct level1 : level0 
{ 
    virtual void foo() { cout <<" level1 " << endl; } 
}; 

struct level2 : level1 
{ 
    virtual void foo() { cout <<" level2 " << endl; } 
}; 

struct level3 : level2 
{ 
    using level1::foo; 
}; 

int main() 
{ 
    level1* l1 = new level3; 
    l1->foo(); 
    level3 l3; 
    l3.foo(); 
    return 0; 
} 

il codice di cui sopra utilizzando gcc restituisceUna dichiarazione di utilizzo dovrebbe nascondere una funzione virtuale ereditata?

level2 
level1 

ma in ICC dà

level2 
level2 

Qual è corretto o è undefined dalla norma?

Edit: Questo dimostra c'è un bug di sicuro, si consideri la seguente funzione principale

int main() 
{ 
    level3 l3; 
    l3.foo();    // This prints level1 

    level3* pl3 = &l3; 
    pl3->foo();    // This prints level2 

    level3& rl3 = l3; 
    rl3.foo();    // This prints level1 

    level3& rpl3 = *pl3; 
    rpl3.foo();    // This prints level2 

    return 0; 
} 

Così lo stesso oggetto quando viene utilizzato direttamente produce risultati diversi e quando viene utilizzato tramite un puntatore di stesso tipo produce risultati diversi !!!

+0

Direi che GCC è corretto, ma non ne sono sicuro. –

+0

Divertente, stavo solo esaminando questo ieri. – aschepler

+0

Ho confermato il comportamento con TDM MinGW g ++ 4.4.1. È un bug g ++, per favore segnalalo. Cheers & hth., –

risposta

5

Un esempio nella sezione standard 10.3p2 chiarisce che l'utilizzo delle dichiarazioni non sostituisce le funzioni virtuali.

Questo è un known g++ bug.

Come notato, quando si chiama la funzione membro tramite un riferimento o un puntatore, anziché un caso in cui è noto il tipo dinamico, il bug non si verifica.

+0

+1 per rif. Segnalazione errori. –

+1

+1 per preventivo standard, come per il bug: segnalato nel 2004, ultimo aggiornamento nel 2006 -> Immagino che a nessuno importi davvero il lavoro facile in giro :) –

0

il modo per ottenere level1 level1 naturalmente sarebbe:

struct level3 : level2 
{ 
    virtual void foo() { level1::foo(); } 
}; 

Il tuo "usando" direttiva sembra essere informare il compilatore che se si dispone di un Level3 e chiamare foo su di esso, si dovrebbe invocare il level1 versione, ma non lo sovrascrive sulla v-table.

gcc sembra sbagliato a causa dell'inconsistenza, non sono sicuro di icc perché non so cosa indica lo standard.

1

using level1::foo; introduce una funzione foo nella classe level3 che fa riferimento a level1::foo.

In una dichiarazione di utilizzo utilizzata come dichiarazione membro, lo specifi- catore del nome nidificato deve nominare una classe base della classe da definire. Tale dichiarazione d'uso introduce l'insieme di dichiarazioni trovate per la ricerca del nome del membro.

Tuttavia, dal momento che level1::foo è virtuale, credo che chiamandola si dovrebbe chiamare level2::foo, quindi CPI dovrebbe essere giusto.

Non ne sono così sicuro, comunque.