5 Stimmen

SmartPointer: Wechsel zwischen Basis- und abgeleiteten Klassen

Angenommen, Sie haben eine Funktion wie diese:

SmartPtr<A> doSomething(SmartPtr<A> a);

Und Klassen wie diese :

class A { }
class B : public A { }

Und jetzt mache ich das:

SmartPtr<A> foo = new B();
doSomething(foo);

Jetzt würde ich gerne wieder eine SmartPtr<B> Objekt aus doSomething .

SmartPtr<B> b = doSomething(foo); 

Ist das möglich? Welche Art von Guss muss ich machen?
Im Moment habe ich gerade etwas gefunden, das ich hässlich finde:

B* b = (B*)doSomething().get()

Wichtige Hinweise: Ich habe keinen Zugang zu SmartPtr y doSomething() Code.

9voto

BЈовић Punkte 59375

Anstatt das zu tun, können Sie dies tun:

B *b = dynamic_cast< B* >( doSomething.get() );

aber Sie müssen prüfen, ob b NULL ist.

3voto

Jesse McDonald Punkte 109

Für alle, die bei der Suche nach der Vorgehensweise über diese jahrzehntealte Frage stolpern: C++11 hat dynamic_pointer_cast , static_pointer_cast y const_pointer_cast um genau dies zu tun. Nun ist dieses Problem so einfach wie

shared_ptr<B> b=static_pointer_cast<B>(doSomething(foo));

-1voto

Boaz Yaniv Punkte 6166

Sie können Ihre eigene SmartPtrCast-Vorlagefunktion definieren, die etwa so funktioniert:

template <typename DestT, typename SrcT>
inline SmartPtr<DestT> SmartPtrCast(const SmartPtr<SrcT> &src)
{
    return SmartPtr<DestT>(static_cast<DestT*>(src.get()));
}

Dann müssen Sie sich nur noch elegant von A nach B werfen:

SmartPtr<B> b = SmartPtrCast<B>(doSomething(foo));

Caveat Emptor: Dies funktioniert nur, wenn der Smart Pointer, der von doSomething() wird an anderer Stelle referenziert und wird nicht zerstört, wenn sie den Geltungsbereich verlässt. Nach Ihrem Beispiel zu urteilen, ist dies der Fall, aber es ist immer noch nicht so anmutig, und es sollte beachtet werden, dass die beiden Zeiger ihre Referenzzählung nicht teilen (wenn also einer von ihnen zerstört wird, verliert der zweite seine Daten).

Eine bessere Lösung besteht darin, einen der Zeiger zu trennen (wenn SmartPtr eine Trennungsmethode hat). Eine noch bessere Lösung (wenn Sie keine detach-Methode haben oder wenn Sie die Anzahl der Verweise gemeinsam nutzen wollen) ist die Verwendung einer Wrapper-Klasse:

template <typename SrcT, typename DestT>
class CastedSmartPtr
{
private:
    SmartPtr<SrcT> ptr;
public:
    CastedSmartPtr(const SmartPtr<SrcT>& src)
    {
        ptr = src;
    }

    DestT& operator* () const
    {
        return *(static_cast<DestT*> >(ptr.get()));
    }

    DestT* operator->() const
    {
         return static_cast<DestT*> >(ptr.get());
    }

    DestT* get() const
    {
        return static_cast<DestT*> >(ptr.get());
    }
}

template <typename DestT, typename SrcT>
inline SmartPtr<DestT> SmartPtrCast(const SmartPtr<SrcT>& src)
{
    return CastedSmartPtr<SrcT, DestT>(src);
}

Dabei wird ein SmartPtr intern (damit die Referenzzählung ordnungsgemäß gemeinsam genutzt wird) und static_cast es intern zu DestT (ohne Auswirkungen auf die Leistung). Wenn Sie Folgendes verwenden möchten dynamic_cast können Sie dies nur einmal, im Konstruktor, tun, um unnötigen Overhead zu vermeiden. Möglicherweise möchten Sie dem Wrapper auch zusätzliche Methoden hinzufügen, z. B. einen Kopierkonstruktor, einen Zuweisungsoperator, eine Abtrennmethode usw.

-2voto

Giovanni Funchal Punkte 8569
SmartPtr<B> b = dynamic_cast<B*>(doSomething().get())

oder vielleicht etwas wie doSomething().dynamic_cast<B*>() wenn Ihr SmartPtr dies unterstützt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X