سؤال

كما يتطلب بعض التعليمات البرمجية التحويل الضمني بين مصفوفات أنواع مختلفة (على سبيل المثال Matrix<int> ل Matrix<double>)، حددت منشئ نسخة templated Matrix<T>::Matrix(Matrix<U> const&) بدلا من المعيار Matrix<T>::Matrix(Matrix<T> const&):

template <typename T> class Matrix {
public:
    // ...
    template <typename U> Matrix(Matrix<U> const&);
    // ...
private
    unsigned int m_rows, m_cols;
    T *m_data;
    // ...
};

مع إضافة Typecast مناسبة إلى منشئ النسخ، تم تحويل هذه الطريقة بلا تشويه بين مصفوفات أنواع مختلفة. من المستغرب أن يفشل مع خطأ Malloc في الموقف الذي سيعمل فيه منشئ نسخة بسيطة: أين U == T. وبعد بالتأكيد بما فيه الكفاية، زيادة تحميل نسخة النسخة مع الافتراضي Matrix<T>::Matrix(Matrix<T> const&) توقيع يحل المشكلة.

هذا حلا ضعيفا، حيث ينتج عنه الازدواجية بالجملة في رمز المنشئ النسخة (حرفيا نسخة وعجينة غير متغيرة). والأهم من ذلك، أنا لا أفهم لماذا هناك خالية من المزدوج malloc خطأ دون رمز مكرر. علاوة على ذلك، لماذا الحرف السفلية للغاية template <typename T> template <typename U> بناء الجملة هنا بدلا من المعيار، وأكثر إيجازا بكثير، template <typename T, typename U>?

مصدر كامل للطريقة القيبية، مجمعة باستخدام G ++ V4.0.1 على نظام التشغيل Mac OS 10.5.

template <typename T> template <typename U> Matrix<T>::Matrix(Matrix<U> const& obj) {
    m_rows = obj.GetNumRows();
    m_cols = obj.GetNumCols();
    m_data = new T[m_rows * m_cols];

    for (unsigned int r = 0; r < m_rows; ++r) {
        for (unsigned int c = 0; c < m_cols; ++c) {
            m_data[m_rows * r + c] = static_cast<T>(obj(r, c));
        }
    }
}
هل كانت مفيدة؟

المحلول

فشل لأن القالب لا يقمع الإعلان الضمني لمنشئ نسخة. سيكون بمثابة منشئ محول بسيط، والذي يمكن استخدامه لنسخ كائن عند تحديد دقة التحميل الزائد.

الآن، ربما نسخت مصفوفةك في مكان ما، والتي ستستخدم منشئ النسخ المحدد ضمنيا الذي يقوم بنسخة مسطحة. ثم، فإن المصفوفة المنسوخة والنسخة من شأنها أن تقوم في Destructor بحذف نفس المؤشر.

علاوة على ذلك، لماذا الحرف السفلية للغاية template <typename T> template <typename U> بناء الجملة مطلوب

لأن هناك نوعان من القالبين المعنيين: المصفوفة، وهو قالب فئة، ومقبلة قالب البناء. يستحق كل قالب جملة القالب الخاصة به مع المعلمات الخاصة به.

يجب أن تتخلص من <T> في السطر الأول الخاص بك، بالمناسبة. لا يظهر مثل هذا الشيء عند تحديد قالب.

هذا حلا ضعيفا، حيث ينتج عنه الازدواجية بالجملة في رمز المنشئ النسخة

يمكنك تحديد قالب وظيفة العضو، والذي سيقوم بالعمل، وتفويض من كل من منشئ تحويل ونسخ المنشئ. بهذه الطريقة، لا يتكرر الرمز.


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

struct A {
  template<typename T>
  A(T&) { std::cout << "A(T&)"; }
  A() { }
};

int main() {
  A a;
  A b(a); // template wins:
          //   A<A>(A&)  -- specialization
          //   A(A const&); -- implicit copy constructor
          // (prefer less qualification)

  A const a1;
  A b1(a1); // implicit copy constructor wins: 
            //   A(A const&) -- specialization
            //   A(A const&) -- implicit copy constructor
            // (prefer non-template)
}

يمكن أن يحتوي منشئ النسخ على معلمة مرجعية غير الاتصالات أيضا، إذا كان أي من أعضائها

struct B { B(B&) { } B() { } };
struct A {
  template<typename T>
  A(T&) { std::cout << "A(T&)"; }
  A() { }
  B b;
};

int main() {
  A a;
  A b(a); // implicit copy constructor wins:
          //   A<A>(A&)  -- specialization
          //   A(A&); -- implicit copy constructor
          // (prefer non-template)

  A const a1;
  A b1(a1); // template wins: 
            //   A(A const&) -- specialization
            // (implicit copy constructor not viable)
}

نصائح أخرى

أنا لست واضحا تماما من سؤالك، لكنني أظن أن ما يحدث هو أن منشئ النسخ الافتراضي يستخدم في بعض الأماكن في التعليمات البرمجية الخاصة بك. تذكر، ليس فقط الرمز الذي تكتب فيه بالفعل يستخدم منشئ النسخ - يستخدم برنامج التحويل البرمجي أيضا.

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