سؤال

أشعر مثل هذا واحد تم طرحها من قبل ولكن أنا غير قادر على العثور عليه في ذلك, ولا يمكن العثور على أي شيء مفيد على جوجل.ربما "التغاير" ليست الكلمة التي أبحث عنها ، ولكن هذا المفهوم هي مشابهة جدا إلى أنواع الإرجاع طردي على الوظائف ، لذا أعتقد أنه من الصحيح.هذا ما أريد القيام به وأنه يعطي لي خطأ التحويل:

class Base;
class Derived : public Base;

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

تفترض هذه الفئات يتم بلورتها بشكل كامل...أعتقد يمكنك الحصول على هذه الفكرة.فإنه لا يمكن تحويل SmartPtr<Derived> في SmartPtr<Base> بالنسبة ولسبب غير واضح.أذكر أن هذا أمر طبيعي في C++ و العديد من اللغات الأخرى, رغم أن في هذه اللحظة أنا لا أتذكر لماذا.

بلدي جذر السؤال هو:ما هي أفضل طريقة لأداء هذه المهمة العملية ؟ حاليا أنا سحب المؤشر من SmartPtr, صراحة upcasting إلى نوع قاعدة ، ثم التفاف عليه في الجديد SmartPtr من النوع المناسب (لاحظ أن هذا لا يتسرب الموارد بسبب نمت لدينا SmartPtr فئة يستخدم تدخلي إشارة العد).هذا وقت طويل وفوضوي ، خصوصا عندما تحتاج إلى التفاف SmartPtr في آخر كائن...أي الاختصارات ؟

هل كانت مفيدة؟

المحلول

وكل من منشئ نسخة وعامل التعيين يجب أن يكون قادرا على اتخاذ SmartPtr من نوع مختلف ومحاولة نسخ المؤشر من واحدة إلى أخرى. إذا كانت أنواع غير متوافقة، فإن المترجم ويشكو، وإذا كانت متوافقة، وكنت قد تحل مشكلتك. شيء من هذا القبيل:

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
};

نصائح أخرى

SmartPtr<Base> و SmartPtr<Derived> هما متميزة التجسيدات من SmartPtr القالب.هذه فصول جديدة لا يشتركون في الميراث أن Base و Derived لا.وبالتالي المشكلة الخاصة بك.

ما هي أفضل طريقة لأداء هذه المهمة العملية ؟

 SmartPtr<Base> b = d; 

لا يحتج عامل التعيين.هذا استدعاء نسخ-المنشئ (نسخة يتم حذفه في معظم الحالات) و هو بالضبط كما لو كنت كتب:

 SmartPtr<Base> b(d); 

توفير نسخة-المنشئ أن يأخذ SmartPtr<OtherType> وتنفيذ ذلك.نفس الأمر ينطبق على عامل التعيين.سيكون لديك لكتابة نسخة المنشئ و op= مع الأخذ في الاعتبار دلالات SmartPtr.

وقوالب ليست التغاير، وهذا امر جيد. تخيل ما يمكن أن يحدث في حالة التالية:

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!

لتحقيق ما تحاول القيام به، يجب أن يكون لدى الطبقة مؤشر ذكي منشئ templatized، التي تأخذ إما مؤشر ذكي آخر أو مؤشر من نوع آخر. هل يمكن أن يكون نظرة على دفعة :: shared_ptr، التي تفعل ذلك تماما.

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

ويعتمد على الطبقة SmartPtr. إذا كان لديه منشئ نسخة (أو في قضيتك، عامل التعيين) التي تأخذ SmartPtr<T>، حيث T هو نوع شيد مع، فإنه لن يعمل، لأن SmartPtr<T1> لا علاقة لها SmartPtr<T2> حتى لو T1 و T2 هي المتعلقة بالميراث

ولكن، إذا كان لدى SmartPtr و<م> templatized مشغل نسخة منشئ / المهمة، مع TOther معلمة قالب، أن يقبل SmartPtr<TOther>، فإنه يجب أن تعمل.

وبفرض أن لديك السيطرة على الطبقة SmartPtr، والحل هو توفير منشئ قالب:

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.
};

إذا أنواع T و O متوافقة، وأنها ستعمل، إذا لم تكن ستحصل على خطأ ترجمة.

وأعتقد أن أسهل شيء هو توفير التحويل التلقائي إلى SmartPtr آخر وفقا لما يلي:

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;
};

لاحظ أن هذا التطبيق هو قوي بمعنى أن القالب المشغل التحويل لا تحتاج لمعرفته حول دلالات المؤشر الذكية، لذلك لا يحتاج العد إشارة إلى تكرارها الخ.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top