Tür Dönüştürme Operatörleri

C programlama dilinde tür dönüştürme sadece bir tane “cast”(tür dönüştürme) operatörüyle kolaylıkla yapılabiliyordu. Örneğin;

int a = 5;
short b = (short) a; // operator() burda tür dönüştürme operatörü olarak kullanılıyor

C++ da ise durum biraz daha farklı. Tür dönüştürme işlemi biraz daha detaylı olarak ele alınmış. Şöyleki tür dönüştürme işlemini neyi amaçlıyorsanız o amaca uygun tür dönüştürme operatörünü kullanmalısınız. Şimdi tek tek bu operatörleri inceleyelim.

dynamic_cast (dinamik tür dönüştürme operatörü)

Referanslar ve göstericiler için kullanılır. Geri dönüş değeri istenilen türe dönüştürme işlemi başarısız ise NULL’dır. Genel kullanım alanlarından biri çalışma zamanında tür belirlenmesi (Run Time Type Identification) içindir. Örnek kod üzerinden ilerlersek:

#include <iostream>

using namespace std;

class Hayvan
{

public:

virtual void turIsmi(){cout << "Tür ismi: Hayvan" << endl;};
};

class Aslan: public Hayvan
{
public:
virtual void turIsmi() {cout << "Tür ismi: Aslan" << endl;};

};

int main(int argc, char** argv)
{
Hayvan *h1 = new Hayvan();
Hayvan *h2 = new Aslan(); //burda aslında gizli bir tür dönüştürme işlemi var. Yine burda da dynamic_cast operatörü kullanılabilir.
Hayvan *h3;

if ((h3 = dynamic_cast<Aslan*>(h1)) == NULL)
cout << "h1 Aslan türüne dönüştürülemez." << endl;

if ((h3 = dynamic_cast<Aslan*>(h2)) == NULL)
cout << "h2 Aslan türüne dönüştürülemez" << endl;

h3->turIsmi();

delete(h1);
delete(h2);

return 0;
}

Görüldüğü üzere Hayvan ve Aslan türünden birer nesne dinamik olarak oluşturuluyor. Daha sonra bu nesneler
Hayvan türünden bir göstericiye atanıyor.Eğer neden Aslan türünden bir nesne nasıl oluyorda Hayvan* türüne atanıyor diye sorarsanız dilin tasarımından dolayı diye cevaplandırırım. Kaldı ki bu tasarım daha öncede dediğim gibi çalışma zamanında tür belirlememize olanak sağlıyor. Bunun en geniş örneklerini GUI programlamada görebilirsiniz. Neyse konumuza geri dönelim.

Daha sonra ise dynamic_cast operatörüyle bu göstericiler Hayvan* türüne dönüştürülmeye çalışılmış tabi ki bunlardan h1 göstericisi Hayvan türüne ait bir gösterici olduğundan dynamic_cast operatörü NULL dönecektir.

h2 göstericisi(pointer) ise Aslan türünü gösterdiği için tür ödnüştürme işlemi başarılı bir şekilde gerçekleşecek. Ve 32.satırda çağırılan fonksiyon Aslan sınıfına ait olan sanal fonksiyondur.Böylelikle ekrana

Tür ismi: Aslan

yazılacaktır. Eğer burda göstericiler yerine referanslarla işlem yapsaydık başarısızlık durumunda dynamic_cast operatörü bad_cast türünden bir kural dışı nesnesi (exception) fırlatacaktır.

static_cast operatörü
static_cast te dynamic_cast te olduğu gibi dinamiklik söz konusu değildir. Yani çalışma zamanında türün dönüşüp dönüşemediğini belirleyemezsiniz. Dolayısıyla static_cast’te tüm sorumluluk programcıya aittir. Örneğin:

class Hayvan
{

public:

void turIsmi(){cout << "Tür ismi: Hayvan" << endl;};
};

class Aslan: public Hayvan
{
public:
void turIsmi() {cout << "Tür ismi: Aslan" << endl;};

};

int main(int argc, char** argv)
{
Hayvan *h1 = new Hayvan();
Hayvan *h2 = new Aslan();

Aslan *h3;

h3 = static_cast<Aslan*>(h1);

h3->turIsmi();
delete(h1);
delete(h2);

return 0;
}

static_cast operatörüyle Hayvan türünden bir nesne Aslan’a dönüştürülerek yine Aslan* türünden bir göstericiye atanmıştır.
Çalışma zamanında bu kodun ne yapacağı belirsizdir(ambiguity). Bunun haricinde bu operatörle derleyici tarafından gizli(implicit)
bir şekilde yapılan tüm tür dönüştürmelerini de yapabilirsiniz.

reinterpret_cast

Her türlü gösterici türünü her türlü gösterici türüne çevirebilir. Bilinçsiz kullanımı kesinlikle tavsiye edilmez. Aslında basit olarak
göstericinin diğer göstericiye binary olarak kopyalanmasıdır. Hash fonksiyonlarında pratiklik açısından adres olarak kullanılan alanı hash değerine çevirmek için kullanılır. Kullanım alanları oldukça kısıtlıdır. Örneğin;

#include <iostream>

using namespace std;

int main()
{
int a = 5;

unsigned int *b = reinterpret_cast<unsigned int*>(&a + 1);

cout << *b << endl;

return 0;
}

const_cast

Bir türün değişmezliğini manipüle etmemizi sağlar. Örneğin:

#include <iostream>

using namespace std;

void printf(char *p)
{
cout << "char * " << p << endl;
}

int main(int argc, char** argv)
{
const char *s = "islam yasar";

char *p = const_cast<char*>(s);

printf(p);

return 0;
}

Görüldüğü üzere const olan bir nesnenin normalde const olmayan bir nesneye atanması mümkün değil. Bu tür dönüştürme operatörü ile mümkün hale geliyor.

NOT

Madem çalışma zamanında tür belirlemeden bahsettik typeid operatörünü de araya sıkıştıralım.

typeid

bu operatör basitçe çalışma zamanında gelen nesnenin türünü belirlememizi sağlıyor. Daha önce bunu dynamic_cast operatörüyle yapmıştık.

Hayvan *h1 = new Hayvan();
Aslan *h2 = new Aslan();

if (typeid(h1) == typeid(Aslan*))
cout << "h1 Aslan* türünden" << endl;

if (typeid(h2) == typeid(Aslan*))
cout << "h2 Aslan* türünden" << endl;