تبدیل صریح -explicit conversation , تبدیل ضمنی یا implicit conversation
به تبدیل هایی که به صورت آشکار برنامه نویس با نوشتن نوع مورد نظر داخل پرانتز اعلام می کنه تبدیل صریح میگن مثلا :
float b=3.14;
int a=(int) b ; //tabdil sarih ya explicit conversation
char ch='a';
int asc_code=(int) ch ;//explicit conversation
تبدیل های ضمنی تبدیل هایی هستن که بصورت خود کار و مخفی انجام میشن مثلا :
short a=7;
int b;
b=a;//implicit conversation(tabdil khodkar short be int
void foo(string str) {}
foo("qwe")//implicit conversation (inja char* khodkar be std::string tabdil mishe
-تبدیل ضمنی فقط مخصوص انواع داده ای ساده مثل int به short یا char به int ,... نیست و می تونه برای کلاس ها هم اتفاق بیفته
تبدیل های ضمنی در کلاس ها :
داخل کلاس ها در c++ سه جا امکان داره تبدیل ضمنی انجام بشه :
با فرض این که A,B دو کلاس باشن و a شی از کلاس A و b شی از کلاس B باشه
A a;
B b = a; //tabdil shey class A be B ba seda zadan constructor ya typecast operator
a = b; //Tabdil shey class B be A ba seda zadan copy constructor ya typecast operator
b = a; //Tabdil shey class A be B ba seda zadan copy constructor ya typecast operator
توی c++ می تونیم با overload کردن یکسری operator این تبدیل ها رو کنترل کنیم به شکل زیر :
#include <iostream>
using namespace std;
class A {};
class B {
public:
// B b =a in function ro seda mizane
B (const A& x)//copy constructor
{
cout<<"in Copy constructor\n";
}
// a=b in function ro seda mizane
B& operator= (const A& x) //operator =
{
cout<< "In operator =\n";
return *this;
}
// b=a in function ro seda mizane
operator A() //typecast operator
{
cout<< "In type-cast\n";
return A();
}
};
int main ()
{
A a;
B b = a; // calls constructor
a = b; // calls typecast operator
b = a; // calls = Assignment operator
return 0;
}
تبدیل ضمن زمانی که سازنده کلاس اجرا میشه هم ممکنه انجام بشه و مقادیری که به سازنده کلاس فرستاده میشن ممکنه بصورت خودکار به هم تبدیل بشن مثلا کد زیر :
class A {
public:
A(int a)
{}
};
int main ()
{
char x='a';
A a=x;//call constructor
return 0;
}
این جا x قبل از ارسال به تابع بصورت خودکار و ضمنی به int تبدیل میشه و بعد به constructor فرستاده میشه ّبدون هیچ error یا warning ای که خب ممکنه خیلی وقتا باعث بوجود امدن باگ هایی در برنامه بشه برای جلوگیری از این تبدیل ما میایم constructor رو بصورت explicit تعریف می کنیم یعنی :
class A
{
public:
explicit A(int x){cout<<"!";}
};
int main ()
{
char x='a';
A a=x;//errpr
}
با این روش کد بالا ارور میده که onversion from 'char' to non-scalar type 'A' requested|
تبدیل ضمنی یا implicit برای صدا زدن توابع هم ممکنه اتفاق بیفته مثلا فرض کنیم این کلاس رو داریم :
class A {
public:
void func(int a)
{
}
};
حالا ممکنه یک نفر بیاد از داخل main برنامه این تابع رو این جوری صدا بزنه :
A a;
char x='a';
a.func(x);
از اون جایی که explicit رو فقط میشه برای سازنده کلاس تعریف کرد مجبوریم این جا از یک روش دیگه استفاده کنیم یک روشش میتونه این باشه که تمامی حالت های دیگه تابع رو private تعریف کنیم یعنی از template استفاده کنیم مثلا :
#include <iostream>
using namespace std;
class A {
public:
void func(int a){}
private:
template <class T>
void func(T){}
//ya
template <class T>
void func(T){} = delete ;
};
int main ()
{
char x='a';
A a;
a.func(x);//error
}
کد بالا الان ارور میده و اجرا نمیشه .