تبدیل‌ صریح

تبدیل صریح از زبان C به ارث رسیده است که به آن C-style cast گفته می‌شود. برای مثال به منظور تبدیل صریح یک عدد اعشاری به یک عدد صریح که منجر به از بین رفتن بخش اعشاری آن می‌شود، نوع داده int را داخل یک پرانتز و سمت چپ عدد اعشاری مورد نظر قرار می‌دهیم:

int  intVar   = (int)10.5;      // double demoted to int
char charVar  = (char)intVar ;  // int demoted to char

C-style cast برای انجام تبدیل‌های صریح بین انواع داده اولیه مناسب است که از زبان C به ارث رسیده است. از C-style cast می‌توان برای تبدیل صریح بین کلاس‌ها و اشاره گرها نیز استفاده کرد ولی به منظور کنترل بیشتر بر روی انواع تبدیل‌ها، در ++C چهار نوع تبدیل صریح جدید که به آن new-style cast می گویند ارائه شده است. این تبدیل‌ها عبارتند از:

static_cast     <new_type> (expression)
reinterpret_cast<new_type> (expression)
const_cast      <new_type> (expression)
dynamic_cast    <new_type> (expression)

همانطور که در بالا نیز مشاهده می‌کنید، در این ساختار جدید عبارتی که می‌خواهیم تبدیل کنیم (expression) را داخل پرانتز قرار می‌دهیم و به جای new_type، نوعی که می‌خواهیم به آن تبدیل شود را می‌نویسیم. این cast ها کنترل دقیق‌تری را در مورد نحوه انجام تبدیل‌ها در اختیار ما قرار می‌دهند. تفاوت new-style cast با C-style cast این است که اگر یک تبدیل به هر دلیلی انجام نشود، اگر از new-style cast استفاده کرده باشیم، در زمان کامپایل و اگر از C-style cast استفاده کرده باشیم، در زمان اجرا با خطا رو به رو می‌شویم.

Static cast

از static cast برای تبدیل بین انواع متناسب به یک دیگر مورد استفاده قرار می‌گیرد. این نوع تبدیل شبیه به C-style cast است با این تفاوت که محدودیت بیشتری دارد. برای مثال، C-style cast به شما اجازه می‌دهد تا با استفاده از یک اشاره گر از نوع عدد صحیح را به یک کاراکتر اشاره کنید:

char charVar = 10;         // 1 byte
int *p = (int*)&charVar; // 4 bytes

از آنجایی که این تبدیل باعث می‌شود تا با یک اشاره گر 4 بایتی به 1 بایت از حافظه اشاره کنیم، این تبدیل در زمان اجرا یا با خطا رو به رو می‌شود و یا بر روی حافظه‌های همجوار می‌نویسد.

*p = 5; // run-time error: stack corruption

بر خلاف C-style cast، در static cast کامپایلر با بررسی اینکه آیا نوع داده اشاره گرها با یکدیگر متناسب است یا خیر، به برنامه نویس اجازه می‌دهد تا این تبدیل نادرست را در زمان کامپایل متوجه شود.

int *q = static_cast(&charVar); // compile-time error

Reinterpret cast

برای آنکه مشابه کاری که به صورت پشت صحنه در C-style cast اتفاق می افتد، کامپایلر را مجبور کنیم تا یک تبدیل را انجام دهد، می‌توانیم از reinterpret cast استفاده کنیم.

int *r = reinterpret_cast<int*>(&charVar); // forced conversion

با استفاده از این تبدیل می‌توانیم انواعی که با یک دیگر تناسبی ندارند (مانند تبدیل یک اشاره گر از نوع عدد صحیح به یک اشاره گر از نوع کاراکتر) را به یک دیگر تبدیل کنیم. این کار را به سادگی و فقط با یک کپی باینری از داده‌ها، بدون هیچ گونه تغییری در الگوی بیت‌ها انجام می‌شود. توجه داشته باشید که نتیجه این کار در سیستم عامل‌های مختلف می‌تواند متفاوت باشد و در همه جا یکسان نیست. بنابراین از این نوع تبدیل باید با احتیاط استفاده شود.

Const cast

سومین تبدیل صریح const cast می‌باشد. یکی از کاربردهای این تبدیل، افزودن یا حذف مقدار یک متغیر ثابت (constant) می‌باشد.

const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const

اگرچه const cast به شما اجازه می‌دهد تا مقدار یک ثابت را تغییر دهید، ولی اگر این مقدار ثابت در بخش فقط خواندنی (read-only) حافظه قرار داشته باشد می‌تواند باعث بروز خطا در زمان اجرا شود.

*nonConst = 10; // potential run-time error

اگر تابعی مانند زیر داشته باشیم که به عنوان آرگومان یک اشاره گر غیر ثابت را بپذیرد:

void print(int *p) { std::cout << *p; }

حتی اگر تابع هیچ تغییری بر روی آن انجام ندهد، نمی‌توانیم یک متغیر از نوع ثابت را به آن پاس دهیم و در صورت انجام این کار با خطا رو به رو می‌شویم. برای جلوگیری از این خطا، مقدار ثابت خودمان را با استفاده از const cast به تابع ارسال می‌کنیم.

print(&myConst); // error: cannot convert 
                 // const int* to int*
 
print(nonConst); // allowed

C-style cast و new-style cast

به خاطر داشته باشید که شما با استفاده از C-style cast نیز می‌توانید یک مقدار const تغییر دهید ولی بهتر است از new-style cast برای این کار استفاده کنید. دلیل دیگر برای استفاده از new-style cast به جای C-style cast این است که پیدا کردن آن‌ها در سورس کد نسبت به C-style cast آسان‌تر است. به صورت کلی پیدا کردن خطاهای تبدیل صریح، می‌تواند سخت‌تر باشد. دلیل سوم این است که نوشتن new-style cast کمی ناخوشایند و سخت‌تر از C-style cast است و همین ناخوشایند بودن به برنامه نویس کمک می‌کند تا به دنبال راه حل‌های دیگری به غیر از cast بگردد و به صورت بی رویه از این نوع تبدیل‌ها در برنامه نویسی استفاده نکند.