2015-07-25 14 views
5

Ich habe ein ziemlich seltsames Verhalten bei der Verwendung von Auto und Dynamic_cast aufgetreten. Dies ist die Klasse Hierachie ich habe:dynamische Besetzung eine Referenz und Auto

class BaseInterface { 
public: 
    virtual void someMethod()=0; 
}; 

class Derived:public BaseInterface { 
public: 
    virtual void someMethod1()=0; 
    void someMethod()override; 
}; 

Und natürlich gibt es einige Klassen, die alle abgeleiteten Methoden implementieren.

Dann gibt es eine dritte Klasse, die wie folgt aussieht:

class ThirdClass { 
public: 
    void demoMethod(BaseInterface&); 
    void anotherMethod(Derived&); 
}; 

void ThirdClass::demoMethod(BaseInterface& obj) { 
    auto buffer=dynamic_cast<Derived&>(obj); 
    anotherMethod(buffer); 
} 

Wenn ich kompilieren dies mit gcc Ich erhalte eine Fehlermeldung „kann ein Objekt nicht von abstrakten Typ zuweisen“. Während, wenn ich

ersetzen
auto buffer=... 

mit

Derived& buffer=... 

alles kompiliert in Ordnung. Warum ist das der Fall? Erkennt Auto nicht den richtigen Typ oder etwas?

Auch fand ich einen schmutzigen Trick noch Auto benutzen:

void ThirdClass::demoMethod(Base& obj) { 
    auto buffer=dynamic_cast<Derived*>(&obj); 
    anotherMethod(*buffer); 
} 
+4

Ich denke, 'auto' leitet den Typ' Derived buffer' ab, nicht 'Derived & buffer'. – melpomene

+0

Welche Version von g ++ verwenden Sie? Funktioniert gut, um Ihren Code zu kompilieren [nach der Korrektur von Trivial-Tippfehlern wie z. B. kein Rückgabetyp auf 'demoMethod' und keine Vererbung auf' derived'] - sowohl clang ++ 3.7 (etwa zwei Wochen alt) als auch g ++ 4.9.2. –

+0

@MatsPetersson: Wenn der fehlende Rückgabetyp behoben ist, schlägt er in der beschriebenen Weise mit dem Compiler, den Ideon verwendet, fehl: http://ideone.com/UEtfui –

Antwort

6

Sie bekommen Derived von auto. Verwenden Sie stattdessen:

auto & buffer = dynamic_cast<Derived&>(obj); 
5

§7.1.6.4/7:

Wenn eine Variable deklariert einen Platzhalter Typ verwendet wird initialisiert [...] die abgeleitete Rückgabetyp oder Variablentyp wird von der Art bestimmt von seinem Initialisierer. [...] Lassen Sie T den deklarierten Typ der Variablen oder Rückgabetyp der Funktion sein. Wenn der Platzhalter der auto Typspezifizierer ist, wird der abgeleitete Typ anhand der Regeln für Vorlagenargumentabzug ermittelt. [...] erhalten P von T durch Ersetzen der Vorkommen von auto mit entweder einer neuen erfundenen Vorlage Parameter U [...]. Deduce einen Wert für U mit den Regeln der Vorlage Argument Abzug von einem Funktionsaufruf (14.8.2.1), wobei P ist ein Funktionsvorlage Parametertyp und das entsprechende Argument ist die Initialisierer.

Also, um sich mit dem Prozess vertraut zu machen, werfen Sie einen Blick auf die zum Ableiten der Art von buffer verwendet tatsächliche Regel: Was ist, wenn Sie

geschieht ändern
template <typename U> 
void f(U); 

zu

void f(Derived&); 

beim Aufruf f mit einem Lvalue des Typs Derived? Für die Funktionsvorlage wird U eindeutig als Derived abgeleitet, was dann zu einem Ableitungsfehler führt.
Dies entspricht direkt der Abzug des Platzhaltertyps in Ihrem Beispiel - wird durch Derived ersetzt, und das schlägt fehl, wie Derived ist abstrakt.

Generell, wenn Sie

auto obj = …; 

obj schreiben nie wird ein Referenz, sein ebenso U nie als Referenztyp abgeleitet werden, wenn die obige Funktionsvorlage aufrufen.


Verwenden Sie stattdessen auto&:

auto& buffer = dynamic_cast<Derived&>(obj); 

Nun ist PU&:

template <typename U> 
void f(U&); 

U ist natürlich, immer noch als Derived abgeleitet, aber die Art der P - die ist effektiv der Typ buffer - ist Derived&.

+2

lol, "klar" –

+0

@LightnessRacesinOrbit Nun, ich dachte, dass der Fragesteller verwendet wird, um Vorlage Argument Abzug :) – Columbo

+0

@Columbo Um ehrlich zu sein, ich bin nicht. Ich habe gerade mit C++ wie vor 3 Monaten angefangen und bin noch nicht über Vorlagen gestolpert. – SuppenGeist