copy constructor چیه و چه کاربردی داره ؟ - هفت خط کد انجمن پرسش و پاسخ برنامه نویسی

copy constructor چیه و چه کاربردی داره ؟

+3 امتیاز
سلام دوستان من چند جا درباره copy constructor خوندم ولی نفهمیدم کاربردش چیه و کی باید استفاده بشه

میشه به همراه مثال توضیح بدین ؟
سوال شده اسفند 5, 1392  بوسیله ی ماهان (امتیاز 58)   4 10 14
دوباره تگ گذاری شد مهر 9, 1393 بوسیله ی BlueBlade

1 پاسخ

+4 امتیاز
 
بهترین پاسخ

همون جوری که از اسم مشخصه Copy constructor برای کپی کردن داده های یک شی دیگه به داخل کلاس زمان ساخته شدن استفاده میشه .

نحوه نوشتن copy constructor به چه شکل هست ؟

نحوه تعریف copy constructor  مثل تعریف سازنده معمولی هست با این تفاوت که ورودی از نوع خود کلاس هست

. می تونه به یکی از این شکل ها باشه :

A( const A& other );
 A( A& other );

تفاوتی که دارن اینه که مورد اول هم lvalue قبول می کنه هم rvalue ولی مورد دوم فقط lvalue .(تفاوت lvalue و rvalue )

اکثر مواقع   کاری که توی copy constructor انجام میشه کپی کردن مقدار های private کلاس  ورودی به کلاس مورد نظر هست . 

مثال  :

#include <iostream>
class A
{
public:
	A(int value){ data_ = value; }
	A(const A& other)
	{ 
		this->data_ = other.data_;
	}
	int data(){ return data_; };
private :
	int data_;
};


int  main()
{
	A a(2);
	A b = a;//inja copy constructor seda zade mishe va data dakhele b  2 mishe
	std::cout << b.data();//2 chap mishe
}

 

آیا همیشه لازم داریم copy constructor  را بنویسیم ؟

خیر class ها  یک copy constructor بصورت پیش فرض  دارن که خیلی وقت ها بدرستی کار می کنه .

مثلا فرض کن این class رو داریم :

class A
{
private:
    vector<int> a;
    string b;
    int c;
    char d;
};

copy constructor پیش فرض کد بالا کاری که می کنه معادله این کده :

 A::A( const A& other ) :
     a( other.a ),
     b( other.b ), 
     c( other.c ),
     d(other.d)
  {}

که  به خوبی هم کار میکنه  و تمام فیلد های کلاس کاملا کپی میشن.

چه جا هایی copy constructor باید نوشته بشه  ؟

زمانی که copy constructor پیش فرض برای ما کافی نباشه .

مثلا فرض کنید یکی از اعضای کلاس اشاره گر باشه زمانی که از copy constructor استفاده می کنین آدرس اشاره گر مورد نظر کپی میشه یعنی هر دو تا شی از کلاس اشاره گر داخلشون به یک محل از حافظه اشاره می کنه .

حالا فرض کنین یکی از کلاس ها اشاره گرش پاک بشه (صدا زدن destructor مثلا) که این کار باعث میشه  اشاره گر اون یکی کلاس هم به محل نادرستی از حافظه اشاره می کنه و این جاست که در صورت استفاده از شی اول برنامه زمان اجرا خطا میده .

در این جور موارد ما نیاز داریم که اصطلاحا deep copy رو داخل copy constructor  انجام بدیم یعنی یک اشاره گر جدید بسازیم و تک تک خونه های آرایه رو کپی کنیم   (البته توی c++ بهتره که از اشاره گر های خالی تا اون جایی که میشه  استفاده نشه و از vector یا smart pointer ها استفاده کنین . )

مثال :

class A
{
public:
    A()
    {
        size_=10;
        data_=new int[size_];
        //...
    }

    A(const A& other)
    {
        delete[] data_;
        data_=new int[other.size_];
        memcpy(data_,other.data_,sizeof(int)*other.size_);
    }

private:
    int *data_;
    int size_;
};

چه جاهایی copy constructor صدا زده میشه ؟

هر جا که کپی کردن زمان ساخت شی از کلاس لازم باشه مثلا زمان ارسال متغیر به تابع بدون refrence یا زمان مساوی قرار دادن 2 شی از کلاس  زمان ساخت یکی و...

class A
{
public:
    A(){}
    A(const A& other){cout<<"In copy constructor\n";}
};

void func(A a)//call copy constructor
{

}

A factory()
{
    static A a;
    return a;
}

int  main()
{
    A a;
    func(a);
    A b=a;//call copy constructor
    A c=factory();//call copy constructor
}

 

البته میشه copy constructor رو به شکل explicit هم برای جلوگیری از تبدیل های نا خواسته تعریف کنین که توی لینک زیر توضیح داده شده .

explicit چیست ؟

 از c++11 به بعد move constructor هم اضافه شده  که این جا توضیح داده شده :move semantic 

 

پاسخ داده شده اسفند 6, 1392 بوسیله ی BlueBlade (امتیاز 15,315)   15 18 89
ویرایش شده شهریور 6, 1393 بوسیله ی BlueBlade
سلام. در قسمتی که گفتید "چه جاهایی copy constructor صدا زده میشه ؟" در مثال اول زمانی که به تابع A factory() اجرا میشه چرا وقتی به return a می رسیم به سراغ سازنده کپی میره در حالی که برای static A a به سراغ سازنده اصلی کلاس میره؟
static A a صرفا ساختن یک شی و صدا زدن سازنده پیش فرض  هست واژه static هم بخاطر این هستش که فقط دفعه اول که تابع اجرا میشه شی ساخته بشه .
در مورد return کردن return دو تا کپی انجام میده :‌
۱ـ کپی مقداربازگشتی به یک مقدار موقت
۲ـ کپی مقدار موقت بجایی که صدا زده شده
در موردشون اینجا توضیح دادم
http://goo.gl/dNBOS8
مورد اول رو کامپایلر optimize و حذف می کنه .
مورد دوم " کپی کردن بجایی که صدا زده شده " هست پس A c=factory();  میشه معادل A c=a که چون زمان ساخت شی از = استفاده کردیم copy constructor صدا زده میشه .
...