2012-06-20 12 views
18

Spero che il titolo descrive in realtà quello che volevo chiedere ...C++ chiamata di metodo e di risoluzione della visibilità tipo ambiguità

Ho scritto un pezzo di codice che compila con gcc e lavora come volevo. Tuttavia, non viene compilato con llvm e il codice viene eseguito diversamente quando è compilato con icc!
Ecco un esempio del problema:

#include <iostream> 

using std::cout; using std::endl; 

class A { 
public: 
    virtual void foo() { cout << "A::foo()" << endl; } 
}; 

class B : public A { 
public: 
    typedef A base; 
    virtual void foo() { cout << "B::foo()" << endl; } 
}; 

int main() { 
    typedef B base; 
    base* bp = new B(); 
    bp->base::foo(); 
} 

uscita gcc: A :: foo()
ICC uscita: B :: foo()

qualcuno potrebbe spiegare che cosa fa lo standard dicono di questo caso?

+5

Direi che è un bug in GCC e ICC, poiché 'B :: base' non è un _member_ di' B', il che significa che non dovrebbe essere possibile accedervi come membro ('bp-> base'). –

+1

Sono d'accordo con @JoachimPileborg, inoltre 'base' potrebbe essere interpretato come B in questo ambito. Hai compilato con le bandierine di Warnings? (-Wall per gcc) – Geoffroy

+1

Non è solo un comportamento indefinito, perché 'main' non è della forma richiesta? Sembra che tutti i compilatori abbiano ragione. –

risposta

7

Da C++ 11, §3.4.5/4:

Se l'espressione id di un membro della classe accede è un id qualificato del modulo
 
    class-name-or-namespace-name::... 
il nome-nome-classe-o-nome-spazio successivo a. oppure -> viene prima cercato l'operatore nella classe dell'espressione dell'oggetto e viene utilizzato il nome, se trovato. Altrimenti è cercato nel contesto dell'intera espressione postfix.

Non penso che possa essere più chiaro. Questo trova B::base, quindi l'uscita dovrebbe essere A::foo().

+0

Grazie per l'aiuto, voi ragazzi siete fantastici. Questo particolare paragrafo è davvero molto chiaro ed esattamente al punto! – Nowakus

6

Penso che questa parte dello standard è rilevante:

3.4.3.1 I membri della classe [class.qual]

1) Se il nested-nome-identificatore di una qualificata id nomina un classe, il nome specificato dopo il identificatore dei nomi nidificati viene esaminato nell'ambito della classe (10.2), tranne per i casi elencati di seguito. Il nome deve rappresentare uno o più membri di quella classe o di una delle sue classi di base (clausola 10). [Nota: è possibile fare riferimento a un membro della classe usando un id qualificato in qualsiasi punto nel suo ambito potenziale (3.3.7). -end note] Le eccezioni a la regola di ricerca nome sopra sono le seguenti:

- un nome del distruttore è cercato come specificato in 3.4.3;

- un ID di conversione di un ID funzione di conversione viene ricercato nello stesso modo di un id di tipo di conversione in un accesso di membro di classe (vedere 3.4.5);

- i nomi in un argomento modello di un modello id sono cercati nel contesto in cui si verifica l'intera espressione postfix.

- la ricerca di un nome specificato in una dichiarazione using (7.3.3) trova anche nomi di classe o enumerazione nascosti all'interno della stessa portata (3.3.10).

in questo caso sembra "nominare" una classe, quindi la ricerca viene eseguita nell'ambito della classe. Non vedo come si possa applicare uno qualsiasi dei casi di eccezione, quindi è lo scopo della classe, in quanto tale base equivale a A.

(5.1.1-8 indica che si tratta di un qualificato-id in questo caso e che vale 3.4.3.1)

+0

concordato. Sembra abbastanza chiaro anche a me. Il codice è corretto, ben definito e l'output dovrebbe essere 'A :: foo'. –

Problemi correlati