2012-06-20 4 views
18

Ich hoffe, der Titel beschreibt eigentlich das, was ich ...C++ Methodenaufruf und Typ Bereichsauflösungs Mehrdeutigkeit

fragen wollte, schrieb ich ein Stück Code, der mit gcc kompiliert und arbeitet als ich gedacht. Allerdings kompiliert es nicht mit llvm und der Code wird anders ausgeführt, wenn mit ICC kompiliert! Hier
sind ein Beispiel für das Problem:

#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(); 
} 

gcc Ausgabe: A :: foo()
icc Ausgang: B :: foo()

Könnte jemand erklären, was der Standard sagen hat über dieser Fall?

+5

Ich würde sagen, es ist ein Fehler in GCC und ICC, da 'B :: base' kein _Member_ von' B' ist, was bedeutet, dass es nicht möglich sein sollte, darauf als Member zuzugreifen ('bp-> Basis "). –

+1

Ich stimme @JoachimPileborg zu, außerdem könnte 'base' in diesem Umfang als B interpretiert werden. Haben Sie mit Warning Flags kompiliert? (-Wall for gcc) – Geoffroy

+1

Ist das nicht nur undefiniertes Verhalten, weil 'main' nicht von der benötigten Form ist? Sieht so aus, als hätten alle Compiler Recht. –

Antwort

7

aus C++ 11, §3.4.5/4:

Wenn der ID-Ausdruck in einem Klassenmitgliedszugriff eine qualifizierte ID des Formulars
 
    class-name-or-namespace-name::... 
der Klassenname-oder-Namespacename nach dem. oder -> Der Operator wird zuerst in der Klasse des Objektausdrucks nachgeschlagen und der Name, falls gefunden, wird verwendet. Ansonsten wird im Kontext des gesamten Postfix-Ausdrucks nachgeschlagen.

Ich glaube nicht, dass es klarer sein kann. Dies findet B::base, daher sollte der Ausgang A::foo() sein.

+0

Danke für Hilfe, ihr seid super. Dieser spezielle Absatz ist in der Tat sehr klar und genau auf den Punkt! – Nowakus

6

Ich denke, dieser Teil der Norm relevant ist:

3.4.3.1 Klassen Mitglieder [class.qual]

1) Wenn die verschachtelten-name-Bezeichner einer qualifizierten Nummer eines nominiert Klasse, der Name nach dem geschachtelte-namespecifier wird im Bereich der Klasse (10.2), nachgeschlagen, mit Ausnahme der unten aufgeführten Fälle. Der Name soll einen oder mehrere Mitglieder dieser Klasse oder einer ihrer Basisklassen (Ziffer 10) repräsentieren. [Hinweis: Ein Klassenmitglied kann unter Verwendung einer qualifizierten ID an einem beliebigen Punkt in seinem möglichen Geltungsbereich (3.3.7) angesprochen werden. -end note] Die Ausnahmen zu der oben genannten Namens-Lookup-Regel sind die folgenden:

- ein Destruktor Name ist nachgeschlagen wie in 3.4.3 angegeben;

- Eine Konvertierungstyp-ID einer Konvertierungsfunktions-ID wird auf die gleiche Weise wie eine Konvertierungs-ID in einem Klassenmemberzugriff gesucht (siehe 3.4.5); Die Namen in einem Template-Argument einer Template-ID werden im Kontext nachgeschlagen, in dem der gesamte Postfix-Ausdruck auftritt.

- Die Suche nach einem Namen , der in einer using-Deklaration (7.3.3) angegeben ist, findet auch Klassen- oder Aufzählungsnamen, die innerhalb desselben Bereichs versteckt sind (3.3.10).

base:: in diesem Fall scheint eine Klasse "nominieren", so dass das Nachschlagen im Rahmen der Klasse erfolgt. Ich sehe nicht, wie einer der Ausnahmefälle könnte gelten, so ist es der Bereich der Klasse, wie base entspricht A.

(5.1.1-8 zeigt an, dass es eine qualifizierte-ID in diesem Fall, und dass gilt 3.4.3.1)

+0

Einverstanden. Es scheint mir auch ziemlich klar zu sein. Der Code ist korrekt, gut definiert und die Ausgabe sollte "A :: foo" lauten. –