Verilen tip için template bir fonksiyon oluştururken, derleyici template fonksiyonun bir kopyasını çıkartır ve template tip parametrelerini istenilen tiplerle değiştirir. Bu, özel bir fonksiyonun oluşturulan her tip için aynı uygulamaya sahip olması anlamına gelmektedir. Genellikle böyle olması istenir, bazen de belirli bir veri tipi için template fonksiyonu farklı implemente etmek gereken durumlar oluşabilir.
C++:
template <class T>
class Depo
{
private:
T m_deger;
public:
Depo(T deger){
m_deger = deger;
}
C++:
~Depo(){}
void yazdir(){
std::cout << m_deger << std::endl;
}
};
Yukarıdaki verdiğim kod çoğu veri tipi için düzgün çalışacaktır:
C++:
int main()
{
Depo<int> iDeger(5);
Depo<double> dDeger(6.7);
iDeger.yazdir();
dDeger.yazdir();
return 0;
}
Ekran Çıktısı:
5
6.7
Eğer sadece double değerleri bilimsel notasyonla yazdırmak istenirse fonksiyon template özelleştirme kullanılabilir. Oluşturulması gayet basittir: özelleştirilen fonksiyon tanımlanır (üye fonksiyonsa sınıf tanımlamasının dışında yapılır), template tipleri istenilen tiplerle değiştirilir.
C++:
template <>
void Depo<double>::yazdir(){
std::cout << std::scientific << m_deger << std::endl;
}
Derleyici Depo<double>::yazdir()
fonksiyonunu oluşturacağı zaman zaten bu fonksiyonun oluşturulduğunu görecek ve bir kopya oluşturmak yerine bu fonksiyonu kullanacaktır.
template <> derleyiciye bunun bir template fonksiyon olduğunu fakat herhangi bir template parametre bulundurmadığını belirtir.
Ekran Çıktısı:
5
6.700000e+000
Şimdi, template özelleştirmenin kullanışlı olabileceği bir örneğe bakalım. Template Depo sınıfını char* veri tipiyle kullandığımızda ne olduğunu görelim:
C++:
int main()
{
//Dinamik olarak geçici bir string için yer ayrılır
char* string = new char[40];
std::cout << "Isim: ";
std::cin >> string;
//string depolanır
Depo<char*> deger(string);
//geçici string silinir
delete[] string;
//değer yazdırılır
deger.yazdir();
}
Depo char* tipi için oluşturulduğunda Storage<char*> yapıcı fonksiyonu aşağıda gösterdiğim gibi şöyle gözükür:
C++:
template <>
Depo<char*>: Depo(char* deger){
m_deger = deger;
}
Diğer bir deyimle sadece işaretçi ataması yapılır. Sonuç olarak m_deger string olarak aynı hafıza alanına işaret eder. main() içerisinde string silindiğinde m_deger’in işaret ettiği değeri silinmiş olunur. Bu yüzden yazdırılmaya çalışıldığında alakasız bir çıktı alınır.
Bu sorun template özelleştirme ile çözülebilir. İşaretçi ataması yerine yapıcı aşağıda kodlarını vermiş olduğum fonksiyona girilen stringin kopyası oluşturtulur.
C++:
template <>
Depo<char*>: Depo(char* deger){
int uzunluk = 0;
while (deger[uzunluk] != 0)
++uzunluk;
++uzunluk;
m_deger = new char[uzunluk];
for(int sayac = 0; sayac < uzunluk; ++sayac)
m_deger[sayac] = deger[sayac];
}
Artık Depo<char*> tipinde bir değişken için yer alınırken varsayılan yerine bu yapıcı fonksiyon kullanılacak. Sonuç olarak m_deger stringin bir kopyasını alacak yani string silindiğinde m_deger etkilenmeyecektir.
Yalnız Depo<char*> tipi için hafıza sızıntısı oluşacaktır çünkü m_deger silinmeyecektir. Bu da Depo<char*> yıkıcı fonksiyonunun özelleştirilmesiyle çözülebilir:
C++:
template <>
Depo<char*>::~Depo(){
delete[] m_deger;
}
Umarım Faydalı Olmuştur....