Frage

Ich fühle mich wie dieser zuvor gestellt wurde, aber ich bin nicht in der Lage es auf SO zu finden, noch kann ich nichts finden nützlich bei Google. Vielleicht für „covariant“ ist nicht das Wort, das ich bin auf der Suche, aber das Konzept ist sehr ähnlich Rückgabetypen auf Funktionen kovariant, so dass ich denke, es ist wahrscheinlich richtig. Hier ist, was ich tun möchte, und es gibt mir einen Compiler-Fehler:

class Base;
class Derived : public Base;

SmartPtr<Derived> d = new Derived;
SmartPtr<Base> b = d; // compiler error

Nehmen wir die Klassen voll prall sind ... Ich glaube, Sie bekommen die Idee. Es kann keine SmartPtr<Derived> in eine SmartPtr<Base> aus irgendeinem Grund unklar konvertieren. Ich erinnere daran, dass dies normal ist in C ++ und vielen anderen Sprachen, obwohl im Moment kann ich mich nicht erinnern, warum.

Meine Wurzel Frage ist: Was ist der beste Weg, um diese Zuordnung Operation auszuführen? Derzeit bin ich um den Zeiger aus dem SmartPtr ziehen, explizit in den Basistyp Upcasting, dann ist es in einem neuen SmartPtr des entsprechenden Typs Einwickeln (beachten Sie, dass dies nicht Ressourcen, weil unsere home-grown SmartPtr Klasse verwendet intrusive Referenz undichte Zählen). Das ist lang und chaotisch, vor allem, wenn ich dann wickeln müssen, um den SmartPtr noch in einem anderen Objekt ... alle Verknüpfungen?

War es hilfreich?

Lösung

Sowohl die Copykonstruktor und der Zuweisungsoperator sollte eine SmartPtr eines anderen Typs übernehmen können und versuchen, den Zeiger von einem zum anderen zu kopieren. Wenn die Typen nicht kompatibel sind, wird der Compiler beschweren, und wenn sie kompatibel sind, haben Sie Ihr Problem gelöst. So etwas wie folgt aus:

template<class Type> class SmartPtr
{
    ....
    template<class OtherType> SmartPtr(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> copy constructor

    template<class OtherType> SmartPtr<Type> &operator=(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> assignment operator
};

Andere Tipps

SmartPtr<Base> und SmartPtr<Derived> sind zwei unterschiedliche Ausprägungen eines der SmartPtr Vorlage. Diese neuen Klassen nicht teilen das Erbe, das Base und Derived tun. Daher Ihr Problem.

  

Was ist der beste Weg, um diese Zuordnung Operation auszuführen?

 SmartPtr<Base> b = d; 

Hat aufrufen nicht Zuweisungsoperator. Dies ruft die Kopie-ctor (die Kopie wird in den meisten Fällen elided) und ist genau so, wie wenn Sie schrieb:

 SmartPtr<Base> b(d); 

Geben Sie für eine Kopie-Ctor, die eine SmartPtr<OtherType> nimmt und umzusetzen. Das Gleiche gilt für den Zuweisungsoperator. Sie müssen die Kopie-Ctor und op schreiben = unter Berücksichtigung der Semantik von SmartPtr.

Vorlagen sind nicht covariant, und das ist gut; Vorstellen, was im folgenden Fall passieren würde:

vector<Apple*> va;
va.push_back(new Apple);

// Now, if templates were covariants, a vector<Apple*> could be
// cast to a vector<Fruit*>
vector<Fruit*> & vf = va;
vf.push_back(new Orange); // Bam, we just added an Orange among the Apples!

Um das zu erreichen, was Sie zu tun versuchen, muss die Intelligenter Zeiger-Klasse haben einen templatized Konstruktor, die entweder einen anderen Intelligenter Zeiger oder einen Zeiger eines anderen Typs nimmt. Sie konnten einen Blick auf boost :: shared_ptr haben, was das genau das tut.

template <typename T>
class SmartPointer {

    T * ptr;

  public:
    SmartPointer(T * p) : ptr(p) {}
    SmartPointer(const SmartPointer & sp) : ptr(sp.ptr) {}

    template <typename U>
    SmartPointer(U * p) : ptr(p) {}

    template <typename U>
    SmartPointer(const SmartPointer<U> & sp) : ptr(sp.ptr) {}

    // Do the same for operator= (even though it's not used in your example)
};

Abhängig von der SmartPtr Klasse. Wenn es hat einen Copy-Konstruktor (oder in Ihrem Fall Zuweisungsoperator), die SmartPtr<T> nimmt, wobei T die Art ist es mit gebaut wurde, dann wird es nicht funktionieren, weil SmartPtr<T1> in keinem Zusammenhang ist auch SmartPtr<T2> wenn T1 und T2 im Zusammenhang mit Vererbung.

Wenn jedoch SmartPtr hat eine templatized Copykonstruktor / Zuweisungsoperator, mit Template-Parameter TOther, die SmartPtr<TOther> akzeptiert, dann sollte es funktionieren.

Angenommen, Sie die Kontrolle über die SmartPtr Klasse haben, ist die Lösung, die einen Templat-Konstruktor zur Verfügung zu stellen:

template <class T>
class SmartPtr
{
    T *ptr;
public:

    // Note that this IS NOT a copy constructor, just another constructor that takes 
    // a similar looking class.
    template <class O>
    SmartPtr(const SmartPtr<O> &src)
    {
        ptr = src.GetPtr();
    }
    // And likewise with assignment operator.
};

Wenn die T und O-Typen kompatibel sind, wird es funktionieren, wenn sie nicht Sie einen Compiler-Fehler erhalten.

Ich denke, die einfachste Sache zu einem anderen SmartPtr automatische Konvertierung zur Verfügung zu stellen ist nach dem folgenden:

template <class T>
class SmartPtr
{
public:
    SmartPtr(T *ptr) { t = ptr; }
    operator T * () const { return t; }
    template <class Q> operator SmartPtr<Q> () const
    { return SmartPtr<Q>(static_cast<Q *>(static_cast<T *>(* this))); }
private:
    T *t;
};

Beachten Sie, dass diese Implementierung im Sinne robust ist, dass der Umwandlungsoperator Vorlage nicht über die Semantik des intelligenten Zeigers nicht zu kennen braucht, so Referenzzählung muss nicht etc repliziert werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top