سؤال

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

لمعرفة ذلك، لقد جعلت الرمز البسيط التالي. يجمع، ولكن يعطيني خطأ وقت التشغيل عند إجراء منشئ النسخ.

أحاول نسخ القيمة فقط من مؤشر الكائن المنسوخ، ولكن تجنب تعيين نفس العنوان.

إذن، ما هو الخطأ هنا؟

    class TRY{
        public:
        TRY();
    ~TRY();
        TRY(TRY const &);

        int *pointer;

        void setPointer(int);
    };


    void TRY::setPointer(int a){
        *pointer = a;

        return;
    }


    TRY::TRY(){}


    TRY::~TRY(){}


    TRY::TRY(TRY const & copyTRY){
        int a = *copyTRY.pointer;
        *pointer = a;
    }



    int main(){

        TRY a;
        a.setPointer(5);

        TRY b = a;

        b.setPointer(8);

        cout << "Address of object a = " << &a << endl;
        cout << "Address of object b = " << &b << endl;

        cout << "Address of a.pointer = " << a.pointer << endl;
        cout << "Address of b.pointer = " << b.pointer << endl;

        cout << "Value in a.pointer = " << *a.pointer << endl;
        cout << "Value in b.pointer = " << *b.pointer << endl;

        return 0;
    }

سأكون استخدام هذا المفهوم للدروس الأخرى مع الكثير من المؤشرات، حيث أحتاج إلى نسخ جميع القيم من كائن إلى الآخر. النسخ ضروري في البداية لهذا الرمز، لذلك أود أن أبقي احتمال نسخ (لن أخفي منشئ النسخ على أنه خاص).

علاوة على ذلك، فإن الطبقة الحقيقية التي أحتاجها إلى تنفيذها لديها مثل 10 مؤشرات، وقد يتغير مع مرور الوقت. أليس هناك طريقة أكثر ذكاء إلى حد ما للحصول على منشئ نسخة عميقة في C ++؟ ...

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

المحلول

مع البيان int* pointer لقد حددت للتو مؤشر ولكن لم تخص أي ذاكرة. أولا، يجب عليك الإشارة إلى موقع الذاكرة المناسبة عن طريق تخصيص بعض الذاكرة مثل هذا: int* pointer = new int. وبعد ثم في منشئ النسخ مرة أخرى، عليك تخصيص الذاكرة للكائن المنسوخ. أيضا، لا تنس الافراج عن الذاكرة باستخدام حذف في المدمر.

آمل أن يساعد هذا المثال:

class B
{

public:
    B();
    B(const B& b);
    ~B();
    void setVal(int val);

private:
    int* m_p;
};

B::B() 
{
    //Allocate the memory to hold an int
    m_p = new int;

    *m_p = 0;
}

B::B(const B& b)
{
    //Allocate the memory first
    m_p = new int;

    //Then copy the value from the passed object
    *m_p = *b.m_p;
}

B::~B()
{

    //Release the memory allocated
    delete m_p;
    m_p = NULL;
}

void B::setVal(int val)
{
    *m_p = val;
}

نصائح أخرى

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

هذا ليس صحيح تماما. عندما يكون لديك مؤشرات في صفك وتخصيص الذاكرة باستخدام new ثم عليك أن تقلق بشأن نسخ منشئ. أيضا، لا تنسى مشغل الواجب والمدير. يجب عليك حذف الذاكرة المخصصة باستخدام delete.

تسمى قانون الثلاثة الكبار.

مثال:

  ~Matrix();  //Destructor
  Matrix(const Matrix& m); //Copy constructor
  Matrix& operator= (const Matrix& m); //Assignment operator

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

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

لقد اكتشفت مؤخرا أنه عندما يكون لدي مؤشرات داخل فئة، أحتاج إلى تحديد منشئ نسخة

في كثير من الأحيان، من الجيد تعطيلها ببساطة عن طريق إعلانها (ومشغل الاعتمادات) الخاصة وغير تنفيذها.

إذا كان لديه مؤشر إلى نوع منتظم ثم

A::A(const A& a):
  pointer_( new int( *a.pointer_ ) )
{
}

إذا كان لديه مؤشر إلى بعض الفئة الأساسية بعد ذلك

A::A(const &a ):
  pointer_( a.pointer_->clone() )
{
}

استنساخ هو تنفيذ نمط النموذج الأولي

لا تنسى حذف المؤشر في المدمر

A::~A()
{
    delete pointer_;
}

لإصلاح مثالك

TRY::TRY(TRY const & copyTRY){
    int a = *copyTRY.pointer;
    pointer = new int(a);
}

مشكلتك موجودة في هذا الخط هنا:

    *pointer = a;

جميع الاشياء التي تحدث عادة في المنشئ الافتراضي الخاص بك لم يحدث حتى الآن، بما في ذلك تخصيص الذاكرة ل *pointer.

الإصلاح هو تخصيص الذاكرة لعدد صحيح. يمكنك استخدام malloc والأصدقاء أو new لهذا، ولكن تأكد من أنها نفس الطريقة التي تستخدمها في منشئك الافتراضي الخاص بك، لأنك تحصل فقط على مدمر واحد، ويجب أن تطابق المكالمات.

إذا كانت النسخة الأعضاء (الضحلة) على ما يرام، فلن تضطر إلى فعل أي شيء. إذا كنت تريد نسخة عميقة، فعليك تخصيص تخزين جديد للنسخ من جميع الأعضاء.

عند كتابة منشئ نسخة، يجب عليك تخصيص الذاكرة لجميع الأعضاء. في حالتك:

TRY::TRY(TRY const & copyTRY){
    pointer = new int(*(copyTry.pointer));
}

مشغل = مشابه بطريقة أو بأخرى، ولكن مع عدم وجود تخصيص الذاكرة.

TRY& operator=(TRY const& otherTRY){
      this->a  = *(otherTry.pointer)
      return *this
}

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

على سبيل المثال، ربما يجب أن يكون هذا العضو الدولي * STD :: متجه بدلا من ذلك.

إذا لم تتمكن من جعل الفصل الافتراضي CASPALABLE / CASPALABLE، فربما يمكنك جعلها غير قابلة للتصوير / قابلة للتصريح عن طريق الإعلان، ولكن لا تنفذ، منشئ نسخة خاصة ومتعييل النسخ.

فقط إذا لم يكن أي مما سبق ممكنا، فهل يجب عليك تطبيق منشئ النسخ الخاص بك أو عامل التعيين.

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