2016-12-01 3 views
0

Ich lese Artikel 28 auf Smart Pointer von Scott Meyers Effektiver C++ und haben die folgende Frage.Mehrdeutigkeit im Funktionsaufruf implizit umwandeln Smart-Zeiger

Eine vollständige Demonstration kann bei http://ideone.com/aKq6C0 gefunden werden.

class Base {}; 
class Derived : public Base {}; 
void foo(Base* b) { cout << "foo called on Base pointer" << endl;} 
Derived *d = new Derived(); 
foo(d); //No problem 

Aber solche implizite Umwandlung kann nicht für Smartpointer, d.h. SmartPtr<Derived> implizit konvertiert werden können, nicht auf SmartPtr<Base> geschehen:

Eine abgeleitete Klasse kann Zeiger implizit auf einen Basisklassenzeiger umgewandelt werden. So verwenden wir ein Mitglied Vorlage für solche Umwandlungen:

template<typename T> 
class SmartPtr { 
public: 
    //constructors, operator->, etc 

    //member template for type conversion 
    template<NewType> 
    operator SmartPtr<NewType>() { 
    return SmartPtr<NewType>(pointee); 
    } 
private: 
    T* pointee;//the raw pointer 
}; 

Dies kann fast arbeiten, aber es kann dazu führen, Zweideutigkeit:

class Remote {}; 
class Base : public Remote {}; 
class Derived : public Base {}; 
void foo(const SmartPtr<Remote>& p) { cout << "remote" << endl;} 
void foo(const SmartPtr<Base>& p) { cout << "base" << endl;} 

SmartPtr<Derived> d(new Derived()); 
foo(d);//compile error: ambiguity 

In diesem Beispiel wird der Compiler nicht weiß, ob es d umwandeln sollte SmartPtr<Base> oder SmartPtr<Remote>, obwohl für einen rohen Zeiger Base offenbar überlegen ist. Das Buch sagt

Das Beste, was wir tun können, ist, Member-Vorlagen zu verwenden, um Konvertierungsfunktionen zu generieren, und dann Casts in den Fällen zu verwenden, in denen Mehrdeutigkeiten auftreten.

Aber wie genau wenden wir hier an? foo(static_cast<SmartPtr<Base>>(d)) kompiliert auch nicht. Aus der Fehlermeldung kann ich sagen, dass der Fehler von der Verwendung von nicht-const Referenz im Copy-Konstruktor SmartPtr kommt. Ich frage mich, was ist der richtige Weg, um den Funktionsaufruf zu machen.

+0

Nicht qustion beantworten zu binden, wäre in der Lage, aber 'Rückkehr SmartPtr (pointe e); 'scheint nicht richtig, Sie brauchen etwas wie' std :: week_ptr ', um dies zu tun –

+0

Sie sollten sich die Standard-Smart-Pointer ansehen, und wie sie Umwandlung von 'std :: shared_ptr ' zu 'std bereitstellen :: shared_ptr 'wenn (und nur wenn)' Derived * 'ist konvertierbar zu' Base * '. –

+0

Ihre Besetzung ist korrekt, was fehlt, ist Code für Ihre Kopierkonstruktoren. Wenn Sie einen haben, der non-const ref nimmt - würden Sie den Fehler erhalten, den Sie erwähnten, wenn Sie ref einfach zu const in Kopie ctor ändern können und Code würde kompilieren (geprüft) –

Antwort

0
//constructors 

Dies ist der wichtigste Teil, die Sie ausgelassen haben :)

Ihre Guss als solche richtig ist, es hängt alles von Reihe von Konstrukteuren Sie haben. Wenn Sie einen haben, der nicht-const ref nimmt - würden Sie den Fehler erhalten, den Sie erwähnten, wenn Sie ref einfach zu const in Kopie ctor ändern können und Code würde kompilieren.

Es kann nicht sehr offensichtlich sein, aber wenn man

return SmartPtr<NewType>(pointee); 

rufen Sie neue SmartPtr<NewType> konstruieren, die T* und NewType und T gibt verschiedene Arten zu akzeptieren. Höchstwahrscheinlich haben Sie nur ctor, das rohen Zeiger desselben Typs akzeptiert (d. H.T* für SmartPtr<T> und für SmartPtr<X>) so Compiler für eine andere converting ctor, Ihre neue SmartPtr und findet Ihre Kopie Ctor zu erstellen, aber es kann nicht neuen Wert nicht const binden ref


Edit:

Wenn Sie mit C++ 11 Hinzufügen ctor Schritt würde auch Ihr Problem lösen, wie es rvalue

SmartPtr(SmartPtr<T>&& other): pointee(other.pointee) { other.pointee = nullptr; } 
+0

Dank für die Hilfe Oleg. Sie können die komplette Definition von 'SmartPtr' in der Ideenseite überprüfen, die ich oben zur Verfügung stellte http://ideone.com/aKq6C0. Ich habe es direkt aus dem Buch genommen, und das Verhalten von 'SmartPtr' entscheidet im Grunde, dass es in seinem Kopierkonstruktor eine nicht-konstante Referenz nehmen muss (so wie das veraltete' auto_ptr'). –

+0

verwenden Sie C++ 11? Sie können Ihr Problem auch lösen, indem Sie move ctor hinzufügen? 'SmartPtr (SmartPtr &&)' .. –

Verwandte Themen