C\C++ tip ceviriciləri

Niyə bəzi C++ proqramçıları C üslubunda tipləri çevirməyi xoşlamır?

C++ proqramlaşdırma dilinin keyfiyyətinə heyran olan proqramçılarin Əsas kimi gətirdikləri arqumentlərdən biri tiplərin təhlükəsizliyidir. Faktiki olaraq C++ kompilyatorlarının bir çoxu bunu həyata keçirməyə sizə imkan verməyəcək:

char& pszString = “Hello World!”;

int* pBuf = pszString; // Xəta: char* tipini int* tipine çevirmək olmaz

…Bu olduqca məqbuldur!

 

Müasir C++ kompilyatorları hələ ki, kohnə kodun uyğunluğunu nəzərə alıb dəstəkləyir və ona görədə

avtomatik belə sintaksisə yol verir: int* pBuf = (int*)pszString; // Bir problemin aradan qaldırılması digər problemin yaranmasına təkan verir.

Ancaq C stilində tipin çevrilməsi təyinatı tip kimi interpretasiya edilməsinə kompilyatoru məcbur edir, hansıki developerin fikrincə olduqca rahatdır, ancaq bu halda məhz developer kompilyatorun xəta bildirişi göstərməsinə ciddi səbəblərinin olması barədə düşünməyi mənasız hesab edir.  Əlbətdə tiplərin təhlükəsizliyi barədə kompilyatorun bildirişini görəndə bəzi developerlər bunu mənasız qəbul edib öz bildiklərini yürüdürlər.

 

Tiplərin çevrilməsində dezavantajların olmasına baxmayaraq bu konsepsiyadan da imtina etmək olmaz. Bir çox situasiyalarda tipi çevirmək uyğunluğ probleminin aradan qaldırılması üçün yeganə yoldur. Bundan əlavə C++ dili əvvəllər C dilində mövcud olmayan təzə çevirici operatoru ilə təchizdir, hansıki obyekt yönümlü proqramlaşdırmada istifadə üçün spesifikdir.

C++ dilinin dörd tip çevirici operatoru mövcuddur:

static_cast

dynamic_cast

reinterpret_cast

const_cast

 

Onların tədbiq olunma sintaksisi eynidir.

 

static_cast – operatoru tiplərlə əlaqəli göstəricilərin çevrilməsində və standart tiplərin açıqca çevrilməsində tətbiq olunur, hansıki əks təqdirdə avtomatik yaxud qeyri aydın gerçəkləşərdi.

Base* pBase = new Derived (); // Derived klasının obyekti

Derived* pDerived = static_cast<Derived*>(pBase); // Qaydasındadır!

// İrarxiyada CUnrelated – Base klası ilə heç bir əlaqəsi yoxdur

CUnrelated* pUnrelated = static_cast<CUnrelated*>(pBase); // Xəta! Yuxarı irarxiyaya çevirmək qadağandır,                                                                                                                                                                         // səbəb tipplərin əlaqəsinin olmamasıdır.

 

dynamic_cast – operatoru yazılışından göründüyü kimi tiplərin static çevrilməsinin tam əksini heyata keçirir. Faktiki olaraq çevirməni proqramın icra mühitində yerinə yetirir. dynamic_cast operatorunda tiplərin çevrilməsinin uğurlu olub olmamasını yoxlayıb aydınlaşdırmaq olar.

Base* pBase = new Derived();

Derived* pDerived = dynamic_cast <Derived*> (pBase);  // İrarxiyada aşağı çevirməni gercəkləşdirmək

if (pDerived) // Çevrilmənin nəticəsini yoxlamaq

pDerived->CallDerivedClassFunction ();

İcraat zamanı obyektin tipinin identifikasiya mexanizmi RTTİ adlanır (runtime type identification)

 

reinterpret_cast – operatoru C stilinə hamısından yaxındır. Bu operator bir obyektin tipinin digər obyektin tipi ilə əlaqəli olub olmamasından asılı olmayaraq tipləri çevirməyə developerə imkan verir. Bu çevirici faktiki olaraq kompilyatoru static_cast operatorunun qadağan etdiyi situasiyani qəbul etməyə məcbur edir. Bu operator drayverlərlə, haradakı məlumat APİ interfeysinin qebul edə biləcək adi tipə çevrilməli olduğu, aşağı səviyyəli proqramlaşdırmada tədbiq edilir. (misal üçün, bəzi APİ funksiyalar baytlarla və axınlarla işləyirlər, unsigned char*):

SomeClass* pObject = new SomeClass ();

unsigned char* pBytes = reinterpret_cast <unsigned char*>(pObject); // Obyekti bayt axını kimi ötürmək lazımdır…

 

const_cast – operatoru obyektə giriş üçün const modifikatorunu söndürməyə imkan verir. Əgər sizdə sual yaranırsa bu çevirici ümumiyyətcə nəyə lazımdır ?! İdeal vəziyyətdə developerlər oz klasslarını düzgün yazırlar, onlar const açar sözlərini tez-tez lazım olan yerlərdə istifadə etməyi unutmurlar. Praktikada isə əfsuslar olsun belə deyil və aşağıdakına uyğun kodlara çox yerlərdə rast gəlmək mümkündür.

class SomeClass

{

public:

// . . .

void DisplayMembers(); // Təqdim etmə funksiyası const modifikasiyası ilə olmalıdır

};

Buna uyğun funksiya yaradanda kompilyasiya zamanı xəta baş verir

void DisplayAllData (const SomeClass& mData)

{

mData.DisplayMembers (); // Xətanın səbəbi: Konstant linkini istifadə etməklə klasın konstant olmayan üzvünün (funksiyasının) çağırışıdır

Belə situasiyalarda köməyə const_cast operatoru gəlir.

Ondan istifadə etmək sintaksisi belədir.

void DisplayAllData (const SomeClass& mData)

{

SomeClass& refData = const_cast <SomeClass&>(mData);

refData.DisplayMembers(); // İcazə verilir!

}

Onuda nəzərə alin ki, konstant olmayan funksiyaların çağırışında const_cast operatorunun tətbiqi axırıncı carəsiz vasitə olmalıdır və konstant obyekti modifikasiya etmək xoşagəlməz nəticələrə səbəb ola biler! Buna da diqqət yetirin const_cast operatoru yalniz göstəricilərlə tətbiq olunur.

void DisplayAllData (const SomeClass* pData)

{

SomeClass* pCastedData = const_cast <SomeClass*>(pData);

pCastedData->DisplayMembers(); // İcazə verilir!

}

Səs: 0. Bəyənilsin Zəifdir

Müəllif: Rizvanov Ferid

Şərh yazın