همون جوری که از اسم مشخصه 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