سلام!

این جلسه قرار است با مفهوم تابع سازنده ی کپی آشنا شده و از آن استفاده کنیم.

تابع سازنده ی کپی یا همان copy constructor، تابعی است که وقتی که ما اقدام به ساخت یک کپی از یک object می کنیم، صدا زده می شود. در حالت های زیر ما در واقع داریم از object کپی می گیریم (این موارد در بعضی از کامپایلر ها فرق می کنند.)؛

۱. موقعی که object مورد نظر را به عنوان ورودی به تابع می دهیم (اگر ورودی تابع از نوع مرجع باشد، دیگر کپی گرفته نمی شود.). به تکه برنامه ی زیر دقت کنید؛

int f( Test testCopy ) {    //testCopy is a copy of test (which declared in main function).
    return 1;
}

int main () {
    Test test;
    cout << f( test ) << endl;
}

۲. موقعی که یک object را return می کنیم (و باز هم نوع خروجی، مرجع نیست.).

Test f () {
    Test test;
    return test;
}
//This function returns a copy of "test", which declared in f function.

۳. هنگامی که از یک object دیگر برای ساخت object مورد نظر خود استفاده می کنید؛

int main () {
    Test t1;
    Test t2( t1 );
}

در تمامی حالت های بالا، کامپایلر به صورت پیش فرض یک تابع آماده دارد. این تابع تمامی عضو های object مورد نظر را در object جدید می ریزد. این کار به نظر درست می آید. ولی وقتی در برنامه ی خود از اشاره گر استفاده کنیم، این کار مشکل ساز خواهد شد. کامپایلر آدرس موجود در اشاره گر را کپی می کند و همین باعث بروز مشکلاتی می شود.

شما می توانید با کمک تابع سازنده کپی (copy constructor) نحوه ی کپی کردن یک object را تعریف کنید. بدنه این تابع به صورت زیر است؛

Test( const Test& );

const بودن ورودی اجباری نیست. ولی معمولا در هنگام کپی کردن نمی خواهیم object منبع تغییر کند. برنامه ی زیر را به دقّت مطالعه کنید؛

#include <iostream>

using namespace std;

class Test {

    private:
    
        int *_ptr;
        
        void setPtr( int* );
        
    public:    
    
        Test( int = 0 );
        ~Test();
        Test( const Test& );
        
        void setPtrValue( int );
        
        int ptrValue() const;
        int *ptr() const;    
        
};

Test::Test( int value ) {
    this->setPtr( new int );
    this->setPtrValue( value );
}

Test::~Test () {
    delete this->ptr();
}

Test::Test( const Test &source ) {
    this->setPtr( new int );
    this->setPtrValue( source.ptrValue() );
}

void Test::setPtrValue( int value ) {
    *( this->ptr() ) = value;
}

void Test::setPtr( int *ptr ) {
    this->_ptr = ptr;
}

int Test::ptrValue () const {
    return *( this->ptr() );
}

int *Test::ptr () const {
    return this->_ptr;
}

void f ( Test test ) {
    cout << test.ptr() << endl;
}

int main () {
    Test test;
    cout << test.ptr() << endl;
    f( test );
    return 0;
}

اگر خروجی برنامه ی بالا را نگاه کنید، می بینید که دو آدرس متفاوت وجود دارند. حال اگر تابع سازنده ی کپی را پاک کنید، می بینید که خروجی برنامه دو آدرس یک سان و در آخر اروری شبیه ارور زیر است؛

double free or corruption (fasttop)

این ارور نشان دهنده ی این است که دوبار از عمل گر delete برای یک اشاره گر استفاده کرده اید.

نکته: توجه داشته باشید که باید حواستان به عمل گر = هم باشد. کامپایلر به طور پیش فرض این عمل گر را هم تعریف کرده است. برای همین هم باز مشکلاتی نظیر مشکلات بالا به وجود خواهند آمد.

تمرین:

یک کلاس آرایه پیاده سازی کنید. برای آن copy constructor بنویسید.

موفق باشید!